issue in fUML (it is not conform with one constraint defined in UML) 8.6.2.2.3 CallBehaviorActionActivation, pg. 282 - FUML Object_ context; if (behavior.context == null) { context = null; } else { // Debug.println("[getCallExecution] behavior context = " + behavior.context.name); context = this.getExecutionContext(); } 8.6.3.2.10 ReadSelfActionActivation, pg, 306 - fUML Reference context = new Reference(); context.referent = this.getExecutionContext(); 11.3.36 ReadSelfAction (from IntermediateActions), pg. 280 - UML 2.4.1 [3] The type of the result output pin is the host classifier. self.result.type = self.context - Two options - one readself returns null for activities in another context (respecting the constraint from UML), or callbehavioraction uses the input flow as context when it is an objecttoken NEW STRATEGY -- always generated an ID semantics Changed one association end owned by locus, to be owned by the association... there is no method generated for this.... should not generate method for this A send signal action activation is an invocation action activation for a send signal action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Loci.*; Java // Get the value from the target pin. If the value is not a reference, then do nothing. // Otherwise, construct a signal using the values from the argument pins and send it to the referent object. SendSignalAction action = (SendSignalAction)(this.node); Value target = this.takeTokens(action.target).getValue(0); if (target instanceof Reference) { Signal signal = action.signal; SignalInstance signalInstance = new SignalInstance(); signalInstance.type = signal; PropertyList attributes = signal.ownedAttribute; InputPinList argumentPins = action.argument; for (int i = 0; i < attributes.size(); i++) { Property attribute = attributes.getValue(i); InputPin argumentPin = argumentPins.getValue(i); ValueList values = this.takeTokens(argumentPin); signalInstance.setFeatureValue(attribute, values, 0); } ((Reference)target).send(signalInstance); } A pin activation is an object node activation for a node that is a pin. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Loci.*; The activation of the action that owns the pin for this pin activation. Java // Add all incoming tokens to the pin. Debug.println("[fire] Pin " + (this.node==null? "": this.node.name + "...")); this.addTokens(incomingTokens); Java // Take only a number of tokens only up to the limit allowed by // the multiplicity upper bound of the pin for this activation. int count = this.countUnofferedTokens(); int upper = -1; // Note: A pin activation used in an expansion activation group // will have this.node == null. if (this.node != null) { upper = ((Pin)(this.node)).multiplicityElement.upper.naturalValue; } TokenList tokens = new TokenList(); // Note: upper < 0 indicates an unbounded upper multiplicity. if (upper < 0 | count < upper) { ActivityEdgeInstanceList incomingEdges = this.incomingEdges; for (int i=0; i<incomingEdges.size(); i++) { ActivityEdgeInstance edge = incomingEdges.getValue(i); int incomingCount = edge.countOfferedValues(); TokenList incomingTokens = new TokenList(); if (upper < 0 | incomingCount < upper - count) { incomingTokens = edge.takeOfferedTokens(); count = count + incomingCount; } else if (count < upper) { incomingTokens = edge.takeOfferedTokens(upper-count); count = upper; } for (int j = 0; j < incomingTokens.size(); j++) { Token token = incomingTokens.getValue(j); tokens.addValue(token); } } } return tokens; An output pin activation is a pin activation for an output pin. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; An invocation action activation is an action activation of an invocation action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; An input pin activation is a pin activation for an input pin. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; Java // Forward the offer to the action activation. [When all input pins are ready, the action will fire them.] this.actionActivation.receiveOffer(); Java // Return true if the total number of values already being offered by this pin plus those being offered // by the sources of incoming edges is at least equal to the minimum multiplicity of the pin. boolean ready = super.isReady(); if (ready) { int totalValueCount = this.countUnofferedTokens() + this.countOfferedValues(); int minimum = ((Pin)this.node).multiplicityElement.lower; ready = totalValueCount >= minimum; } return ready; A call action activation is an invocation action activation for a call action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; The set of execution object for currently ongoing calls made through this call action activation. Java // Get the call execution object, set its input parameters from the argument pins and execute it. // Once execution completes, copy the values of the output parameters of the call execution to the result pins of the call action execution, then destroy the execution. Execution callExecution = this.getCallExecution(); if (callExecution != null) { this.callExecutions.addValue(callExecution); CallAction callAction = (CallAction)(this.node); InputPinList argumentPins = callAction.argument; OutputPinList resultPins = callAction.result; ParameterList parameters = callExecution.getBehavior().ownedParameter; int pinNumber = 1; int i = 1; while (i <= parameters.size()) { Parameter parameter = parameters.getValue(i-1); if (parameter.direction == ParameterDirectionKind.in | parameter.direction == ParameterDirectionKind.inout) { ParameterValue parameterValue = new ParameterValue(); parameterValue.parameter = parameter; parameterValue.values = this.takeTokens(argumentPins.getValue(pinNumber-1)); callExecution.setParameterValue(parameterValue); pinNumber = pinNumber + 1; } i = i + 1; } callExecution.execute(); ParameterValueList outputParameterValues = callExecution.getOutputParameterValues(); pinNumber = 1; i = 1; while (i <= parameters.size()) { Parameter parameter = parameters.getValue(i - 1); if ((parameter.direction == ParameterDirectionKind.inout) | (parameter.direction == ParameterDirectionKind.out) | (parameter.direction == ParameterDirectionKind.return_)) { for (int j = 0; j < outputParameterValues.size(); j++) { ParameterValue outputParameterValue = outputParameterValues.getValue(j); if (outputParameterValue.parameter == parameter) { OutputPin resultPin = resultPins.getValue(pinNumber - 1); this.putTokens(resultPin, outputParameterValue.values); } } pinNumber = pinNumber + 1; } i = i + 1; } callExecution.destroy(); this.removeCallExecution(callExecution); } Java // Terminate all call executions (if any), then terminate the call action activation (self). for (int i = 0; i < this.callExecutions.size(); i++) { Execution execution = this.callExecutions.getValue(i); execution.terminate(); } super.terminate(); Java // Remove the given execution from the current list of call executions. boolean notFound = true; int i = 1; while (notFound & i <= this.callExecutions.size()) { if (this.callExecutions.getValue(i-1) == execution) { this.callExecutions.removeValue(i-1); notFound = false; } } Get the execution object for the called behavior. A call behavior action activation is a call action activation for a call behavior action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; Java // Create and execution for the given behavior at the current locus and return the resulting execution object. // If the given behavior is in the context of a classifier, then pass the current context object as the context for the call. // Otherwise, use a null context. // [Note that this requires the behavior context to be compatible with the type of the current contect object.] Behavior behavior = ((CallBehaviorAction)(this.node)).behavior; Object_ context; if (behavior.context == null) { context = null; } else { // Debug.println("[getCallExecution] behavior context = " + behavior.context.name); context = this.getExecutionContext(); } // Debug.println("[getCallExecution] context = " + context); return this.getExecutionLocus().factory.createExecution(behavior, context); A call operation action activation is a call action activation for a call operation action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; Java // If the value on the target input pin is a reference, dispatch the operation to it and return the resulting execution object. CallOperationAction action = (CallOperationAction)(this.node); Value target = this.takeTokens(action.target).getValue(0); Execution execution; if (target instanceof Reference) { execution = ((Reference)target).dispatch(action.operation); } else { execution = null; } return execution; An action activation is an activity node activation for a node that is an action. import java.util.*; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Loci.*; The activations of the pins owned by the action of this action activation. Whether this action activation is already firing. This attribute is only used if the action for this action activation has isLocallyReentrant = false (the default). If isLocallyReentrant=true, then firing always just remains false. Java // Run this action activation and any outoging fork node attached to it. super.run(); if (this.outgoingEdges.size() > 0) { this.outgoingEdges.getValue(0).target.run(); } this.firing = false; Java // If the action is not locally reentrant, then mark this activation as firing. // Take any incoming offers of control tokens, then concurrently fire all input pin activations. // Note: This is included here to happen in the same isolation scope as the isReady test. this.firing = !((Action)this.node).isLocallyReentrant; TokenList offeredTokens = new TokenList(); ActivityEdgeInstanceList incomingEdges = this.incomingEdges; for (int i = 0; i < incomingEdges.size(); i++) { ActivityEdgeInstance incomingEdge = incomingEdges.getValue(i); TokenList tokens = incomingEdge.takeOfferedTokens(); for (int j = 0; j < tokens.size(); j++) { Token token = tokens.getValue(j); token.withdraw(); offeredTokens.addValue(token); } } Action action = (Action)(this.node); // *** Fire all input pins concurrently. *** InputPinList inputPins = action.input; for (Iterator i = inputPins.iterator(); i.hasNext();) { InputPin pin = (InputPin)(i.next()); PinActivation pinActivation = this.getPinActivation(pin); TokenList tokens = pinActivation.takeOfferedTokens(); pinActivation.fire(tokens); for (int j = 0; j < tokens.size(); j++) { Token token = tokens.getValue(j); offeredTokens.addValue(token); } } return offeredTokens; Java // Do the main action behavior then concurrently fire all output pin activations // and offer a single control token. Then activate the action again, // if it is still ready to fire and has at least one token actually being // offered to it. do { Debug.println("[fire] Action " + this.node.name + "..."); Debug.println("[event] Fire activity=" + this.getActivityExecution().getBehavior().name + " action=" + this.node.name); this.doAction(); incomingTokens = this.completeAction(); } while (incomingTokens.size() > 0); Java // Terminate this action activation and any outgoing fork node attached to it. super.terminate(); if (this.outgoingEdges.size() > 0) { this.outgoingEdges.getValue(0).target.terminate(); } Java // In addition to the default condition, check that, if the action has isLocallyReentrant=false, then the activation is not currently firing, // and that the sources of all incoming edges (control flows) have offers and all input pin activations are ready. // [This assumes that all edges directly incoming to the action are control flows.] boolean ready = super.isReady() & (((Action)this.node).isLocallyReentrant | !this.isFiring()); int i = 1; while (ready & i <= this.incomingEdges.size()) { ready = this.incomingEdges.getValue(i-1).hasOffer(); i = i + 1; } InputPinList inputPins = ((Action)(this.node)).input; int j = 1; while (ready & j <= inputPins.size()) { ready = this.getPinActivation(inputPins.getValue(j-1)).isReady(); j = j + 1; } return ready; Java // Indicate whether this action activation is currently firing or not. return firing; Java // Fire all output pins and send offers on all outgoing control flows. Action action = (Action)(this.node); // *** Send offers from all output pins concurrently. *** OutputPinList outputPins = action.output; for (Iterator i = outputPins.iterator(); i.hasNext();) { OutputPin outputPin = (OutputPin)i.next(); PinActivation pinActivation = this.getPinActivation(outputPin); pinActivation.sendUnofferedTokens(); } // Send offers on all outgoing control flows. if (this.outgoingEdges.size() > 0) { TokenList tokens = new TokenList(); tokens.addValue(new ControlToken()); this.addTokens(tokens); this.outgoingEdges.getValue(0).sendOffer(tokens); } Java // Create node activations for the input and output pins of the action for this activation. // [Note: Pins are owned by their actions, not by the enclosing activity (or group), so they must be activated through the action activation.] Action action = (Action)(this.node); ActivityNodeList inputPinNodes = new ActivityNodeList(); InputPinList inputPins = action.input; for (int i = 0; i < inputPins.size(); i++) { InputPin inputPin = inputPins.getValue(i); inputPinNodes.addValue(inputPin); } this.group.createNodeActivations(inputPinNodes); for (int i = 0; i < inputPinNodes.size(); i++) { ActivityNode node = inputPinNodes.getValue(i); this.addPinActivation((PinActivation)(this.group.getNodeActivation(node))); } ActivityNodeList outputPinNodes = new ActivityNodeList(); OutputPinList outputPins = action.output; for (int i = 0; i < outputPins.size(); i++) { OutputPin outputPin = outputPins.getValue(i); outputPinNodes.addValue(outputPin); } this.group.createNodeActivations(outputPinNodes); for (int i = 0; i < outputPinNodes.size(); i++) { ActivityNode node = outputPinNodes.getValue(i); this.addPinActivation((PinActivation)(this.group.getNodeActivation(node))); } Java // If there are no outgoing activity edge instances, create a single activity edge instance with a fork node execution at the other end. // Add the give edge to the fork node execution that is the target of the activity edge instance out of this action execution. // [This assumes that all edges directly outgoing from the action are control flows, with an implicit fork for offers out of the action.] ActivityNodeActivation forkNodeActivation; if (this.outgoingEdges.size() == 0) { forkNodeActivation = new ForkNodeActivation(); ActivityEdgeInstance newEdge = new ActivityEdgeInstance(); super.addOutgoingEdge(newEdge); forkNodeActivation.addIncomingEdge(newEdge); } else { forkNodeActivation = this.outgoingEdges.getValue(0).target; } forkNodeActivation.addOutgoingEdge(edge); Java // Add a pin activation to this action activation. this.pinActivations.addValue(pinActivation); pinActivation.actionActivation = this; Java // Precondition: The given pin is owned by the action of the action activation. // Return the pin activation corresponding to the given pin. PinActivation pinActivation = null; int i = 1; while (pinActivation == null & i <= this.pinActivations.size()) { PinActivation thisPinActivation = this.pinActivations.getValue(i-1); if (thisPinActivation.node == pin) { pinActivation = thisPinActivation; } i = i + 1; } return pinActivation; Java // Precondition: The action execution has fired and the given pin is owned by the action of the action execution. // Place a token for the given value on the pin activation corresponding to the given output pin. Debug.println("[putToken] node = " + this.node.name); ObjectToken token = new ObjectToken(); token.value = value; PinActivation pinActivation = this.getPinActivation(pin); pinActivation.addToken(token); Java // Precondition: The action execution has fired and the given pin is owned by the action of the action execution. // Place tokens for the given values on the pin activation corresponding to the given output pin. // Debug.println("[putTokens] node = " + this.node.name); for (int i = 0; i < values.size(); i++) { Value value = values.getValue(i); this.putToken(pin, value); } Java // Precondition: The action execution has fired and the given pin is owned by the action of the action execution. // Get any tokens held by the pin activation corresponding to the given input pin and return them // (but leave the tokens on the pin). Debug.println("[getTokens] node = " + this.node.name + ", pin = " + pin.name); PinActivation pinActivation = this.getPinActivation(pin); TokenList tokens = pinActivation.getUnofferedTokens(); ValueList values = new ValueList(); for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); Value value = ((ObjectToken)token).value; if (value != null) { values.addValue(value); } } return values; Java // Precondition: The action execution has fired and the given pin is owned by the action of the action execution. // Take any tokens held by the pin activation corresponding to the given input pin and return them. Debug.println("[takeTokens] node = " + this.node.name + ", pin = " + pin.name); PinActivation pinActivation = this.getPinActivation(pin); TokenList tokens = pinActivation.takeUnofferedTokens(); ValueList values = new ValueList(); for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); Value value = ((ObjectToken)token).value; if (value != null) { values.addValue(value); } } return values; Java // If this action has an outgoing fork node, check that the fork node is the source of the given edge instance. boolean isSource = false; if (this.outgoingEdges.size() > 0) { isSource = this.outgoingEdges.getValue(0).target.isSourceFor(edgeInstance); } return isSource; Java // Test if the given value participates in the given link. FeatureValueList linkFeatureValues = link.getFeatureValues(); boolean participates = false; int i = 1; while (!participates & i <= linkFeatureValues.size()) { participates = linkFeatureValues.getValue(i-1).values.getValue(0).equals(value); i = i + 1; } return participates; Java // Make a Boolean value using the built-in Boolean primitive type. // [This ensures that Boolean values created internally are the same as the default used for evaluating Boolean literals.] LiteralBoolean booleanLiteral = new LiteralBoolean(); booleanLiteral.value = value; return (BooleanValue)(this.getExecutionLocus().executor.evaluate(booleanLiteral)); Java // Concurrently fire all output pin activations and offer a single // control token. Then check if the action should fire again // and, if so, return additional incoming tokens for this. this.sendOffers(); Debug.println("[fire] Checking if " + this.node.name + " should fire again..."); _beginIsolation(); TokenList incomingTokens = new TokenList(); this.firing = false; if (this.isReady()) { incomingTokens = this.takeOfferedTokens(); this.firing = this.isFiring() & incomingTokens.size() > 0; } _endIsolation(); return incomingTokens; Do the required action behavior. A write link action activation is a link action activation for a write link action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; A write structural feature action activation is a structural feature action activation for a write structural feature action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Return the position (counting from 1) of the first occurance of the given value in the given list at or after the starting index, or 0 if it is not found. boolean found = false; int i = startAt; while (!found & i <= list.size()) { found = list.getValue(i-1).equals(value); i = i + 1; } if (!found) { i = 1; } return i - 1; A value specification action activation is an action activation for a value specification action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Evaluate the value specification for the action and place the result on the result pin of the action. ValueSpecificationAction action = (ValueSpecificationAction)(this.node); Value value = this.getExecutionLocus().executor.evaluate(action.value); this.putToken(action.result, value); A test identity action activation is an action activation for a test identity action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the values from the first and second input pins and test if they are equal. (Note the equality of references is defined to be that they have identical referents.) // If they are equal, place true on the pin execution for the result output pin, otherwise place false. TestIdentityAction action = (TestIdentityAction)(this.node); Value firstValue = this.takeTokens(action.first).getValue(0); Value secondValue = this.takeTokens(action.second).getValue(0); Value testResult = this.makeBooleanValue(firstValue.equals(secondValue)); this.putToken(action.result, testResult); A structural feature action activation is an action activation for a structural feature action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // If the structural feature for the action of this activation is an association end, // then get the associated association. Association association = null; if (feature instanceof Property) { association = ((Property)feature).association; } return association; Java // Get the links of the given binary association whose end opposite // to the given end has the given value Property oppositeEnd = this.getOppositeEnd(association, end); ExtensionalValueList extent = this.getExecutionLocus().getExtent(association); LinkList links = new LinkList(); for (int i = 0; i<extent.size(); i++) { ExtensionalValue link = extent.getValue(i); if (link.getFeatureValue(oppositeEnd).values.getValue(0).equals(oppositeValue)) { if (!end.multiplicityElement.isOrdered | links.size() == 0) { links.addValue((Link)link); } else { int n = link.getFeatureValue(end).position; boolean continueSearching = true; int j = 0; while (continueSearching & j < links.size()) { j = j + 1; continueSearching = links.getValue(j-1).getFeatureValue(end).position < n; } if (continueSearching) { links.addValue((Link)link); } else { links.addValue(j-1, (Link)link); } } } } return links; Java // Get the end of a binary association opposite to the given end. Property oppositeEnd = association.memberEnd.getValue(0); if (oppositeEnd == end) { oppositeEnd = association.memberEnd.getValue(1); } return oppositeEnd; A remove structural feature action activation is a write structural feature action activation for a remove structural feature value action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.LociL1.*; Java // Get the values of the object and value input pins. // If the given feature is an association end, then destroy any matching links. // Otherwise, if the object input is a structural value, remove values from the given feature. // If isRemoveDuplicates is true, then destroy all current matching links or remove all values equal to the input value. // If isRemoveDuplicates is false and there is no removeAt input pin, remove any one feature value equal to the input value (if there are any that are equal). // If isRemoveDuplicates is false, and there is a removeAt input pin remove the feature value at that position. RemoveStructuralFeatureValueAction action = (RemoveStructuralFeatureValueAction)(this.node); StructuralFeature feature = action.structuralFeature; Association association = this.getAssociation(feature); Value value = this.takeTokens(action.object).getValue(0); Value inputValue = null; if (action.value != null) { // NOTE: Multiplicity of the value input pin is required to be 1..1. inputValue = this.takeTokens(action.value).getValue(0); } int removeAt = 0; if (action.removeAt != null) { removeAt = ((UnlimitedNaturalValue)this.takeTokens(action.removeAt).getValue(0)).value.naturalValue; } if (association != null) { LinkList links = this.getMatchingLinks(association, feature, value); if (action.isRemoveDuplicates) { for (int i = 0; i < links.size(); i++) { Link link = links.getValue(i); link.destroy(); } } else if (action.removeAt == null) { // *** If there is more than one matching link, non-deterministically choose one. *** if (links.size() > 0) { int i = ((ChoiceStrategy)this.getExecutionLocus().factory.getStrategy("choice")).choose(links.size()); links.getValue(i-1).destroy(); } } else { boolean notFound = true; int i = 1; while (notFound & i < links.size()) { Link link = links.getValue(i-1); if (link.getFeatureValue(feature).position == removeAt) { notFound = false; link.destroy(); } } } } else if (value instanceof StructuredValue) { // If the value is a data value, then it must be copied before // any change is made. if (!(value instanceof Reference)) { value = value.copy(); } FeatureValue featureValue = ((StructuredValue)value).getFeatureValue(action.structuralFeature); if (action.isRemoveDuplicates) { int j = this.position(inputValue, featureValue.values, 1); while (j > 0) { featureValue.values.remove(j-1); j = this.position(inputValue, featureValue.values, j); } } else if (action.removeAt == null) { intList positions = new intList(); int j = this.position(inputValue, featureValue.values, 1); while (j > 0) { positions.addValue(j); j = this.position(inputValue, featureValue.values, j); } if (positions.size()>0) { // *** Nondeterministically choose which value to remove. *** int k = ((ChoiceStrategy)this.getExecutionLocus().factory.getStrategy("choice")).choose(positions.size()); featureValue.values.remove(positions.getValue(k-1) - 1); } } else { if (featureValue.values.size() >= removeAt) { featureValue.values.remove(removeAt-1); } } } if (action.result != null) { this.putToken(action.result, value); } A read link action activation is a link action activation for a read link action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the extent, at the current execution locus, of the association to which the action applies. // For all links that match the link end data, place the value of the remaining "open" end on the result pin. ReadLinkAction action = (ReadLinkAction)(this.node); LinkEndDataList endDataList = action.endData; LinkEndData openEnd = null; int i = 1; while((openEnd == null) & i <= endDataList.size()) { if (endDataList.getValue(i-1).value == null) { openEnd = endDataList.getValue(i-1); } i = i + 1; } ExtensionalValueList extent = this.getExecutionLocus().getExtent(this.getAssociation()); FeatureValueList featureValues = new FeatureValueList(); for (int j = 0; j < extent.size(); j++) { ExtensionalValue value = extent.getValue(j); Link link = (Link)value; if (this.linkMatchesEndData(link, endDataList)) { FeatureValue featureValue = link.getFeatureValue(openEnd.end); if (!openEnd.end.multiplicityElement.isOrdered | featureValues.size() == 0) { featureValues.addValue(featureValue); } else { int n = featureValue.position; boolean continueSearching = true; int k = 0; while (continueSearching & k < featureValues.size()) { k = k + 1; continueSearching = featureValues.getValue(k-1).position < n; } if (continueSearching) { featureValues.addValue(featureValue); } else { featureValues.addValue(k-1, featureValue); } } } } for (int j = 0; j < featureValues.size(); j++) { FeatureValue featureValue = featureValues.getValue(j); this.putToken(action.result, featureValue.values.getValue(0)); } // Now that matching is done, ensure that all tokens on end data input pins // are consumed. for (int k=0; k<endDataList.size(); k++) { LinkEndData endData = endDataList.getValue(k); if (endData.value != null) { this.takeTokens(endData.value); } } A read self action activation is an action activation for a read self action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the context object of the activity execution containing this action activation and place a reference to it on the result output pin. // Debug.println("[ReadSelfActionActivation] Start..."); Reference context = new Reference(); context.referent = this.getExecutionContext(); // Debug.println("[ReadSelfActionActivation] context object = " + context.referent); OutputPin resultPin = ((ReadSelfAction)(this.node)).result; this.putToken(resultPin, context); A read structural feature action activation is an action activation for a read structural feature action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the value of the object input pin. // If the given feature is an association end, then get all values of the that end. // for which the opposite end has the object input value and place them on the result pin. // Otherwise, if the object input value is a structural value, then get the values // of the appropriate feature of the input value and place them on the result output pin. ReadStructuralFeatureAction action = (ReadStructuralFeatureAction)(this.node); StructuralFeature feature = action.structuralFeature; Association association = this.getAssociation(feature); Value value = this.takeTokens(action.object).getValue(0); ValueList resultValues = new ValueList(); if (association != null) { LinkList links = this.getMatchingLinks(association, feature, value); for (int i = 0; i < links.size(); i++) { Link link = links.getValue(i); resultValues.addValue(link.getFeatureValue(feature).values.getValue(0)); } } else if (value instanceof StructuredValue) { // Debug.println("[ReadStructuralFeatureActionActivation] value = " + value +", structural feature = " + feature.name); resultValues = ((StructuredValue)value).getFeatureValue(feature).values; } this.putTokens(action.result, resultValues); A link action activation is an action activation for a link action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Test whether the given link matches the given end data. boolean matches = true; int i = 1; while (matches & i <= endDataList.size()) { matches = this.endMatchesEndData(link, endDataList.getValue(i-1)); i = i + 1; } return matches; Java // Test whether the appropriate end of the given link matches the given end data. boolean matches = false; if (endData.value == null) { matches = true; } else { Property end = endData.end; FeatureValue linkFeatureValue = link.getFeatureValue(end); Value endValue = this.getTokens(endData.value).getValue(0); if (endData instanceof LinkEndDestructionData) { if (!((LinkEndDestructionData)endData).isDestroyDuplicates & !end.multiplicityElement.isUnique & end.multiplicityElement.isOrdered) { int destroyAt = ((UnlimitedNaturalValue)(this.getTokens(((LinkEndDestructionData)endData).destroyAt).getValue(0))).value.naturalValue; matches = linkFeatureValue.values.getValue(0).equals(endValue) && linkFeatureValue.position == destroyAt; } else { matches = linkFeatureValue.values.getValue(0).equals(endValue); } } else { matches = linkFeatureValue.values.getValue(0).equals(endValue); } } return matches; Java // Get the association for the link action of this activation. return (Association)(((LinkAction)(this.node)).endData.getValue(0).end.association); A destroy link action activation is a write link action activation for a destroy link action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.LociL1.*; Java // Get the extent, at the current execution locus, of the association for which links are being destroyed. // Destroy all links that match the given link end destruction data. // For unique ends, or non-unique ends for which isDestroyDuplicates is true, match links with a matching value for that end. // For non-unique, ordered ends for which isDestroyDuplicates is false, match links with an end value at the given destroyAt position. [Must a value be given, too, in this case?] // For non-unique, non-ordered ends for which isDestroyDuplicates is false, pick one matching link (if any) non-deterministically. [The semantics of this case is not clear from the current spec.] Debug.println("[doAction] DestroyLinkAction..."); DestroyLinkAction action = (DestroyLinkAction)(this.node); LinkEndDestructionDataList destructionDataList = action.endData; Debug.println("[doAction] end data size = " + destructionDataList.size()); boolean destroyOnlyOne = false; int j = 1; while (!destroyOnlyOne & j <= destructionDataList.size()) { LinkEndDestructionData endData = destructionDataList.getValue(j-1); destroyOnlyOne = !endData.end.multiplicityElement.isUnique & !endData.end.multiplicityElement.isOrdered & !endData.isDestroyDuplicates; j = j + 1; } LinkEndDataList endDataList = new LinkEndDataList(); for (int i = 0; i < destructionDataList.size(); i++) { LinkEndDestructionData endData = destructionDataList.getValue(i); Debug.println("[doAction] Matching end = " + endData.end.name); endDataList.addValue(endData); } ExtensionalValueList extent = this.getExecutionLocus().getExtent(this.getAssociation()); ExtensionalValueList matchingLinks = new ExtensionalValueList(); for (int i = 0; i < extent.size(); i++) { ExtensionalValue value = extent.getValue(i); Link link = (Link)value; if (this.linkMatchesEndData(link, endDataList)) { matchingLinks.addValue(link); } } // Now that matching is done, ensure that all tokens on end data input pins // are consumed. for (int i = 0; i < destructionDataList.size(); i++) { LinkEndDestructionData endData = destructionDataList.getValue(i); Property end = endData.end; if (!endData.isDestroyDuplicates & !end.multiplicityElement.isUnique & end.multiplicityElement.isOrdered) { this.takeTokens(endData.destroyAt); } Debug.println("[doAction] Consuming tokens for end " + end.name); this.takeTokens(endData.value); } if (destroyOnlyOne) { // *** If there is more than one matching link, non-deterministically choose one. *** if (matchingLinks.size() > 0) { int i = ((ChoiceStrategy)this.getExecutionLocus().factory.getStrategy("choice")).choose(matchingLinks.size()); matchingLinks.getValue(i-1).destroy(); } } else { for (int i = 0; i < matchingLinks.size(); i++) { ExtensionalValue matchingLink = matchingLinks.getValue(i); matchingLink.destroy(); } } A destroy object action activation is an action activation for a destroy object action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the value on the target input pin. // If the value is not a reference, then the action has no effect. Otherwise, do the following. // If isDestroyLinks is true, destroy all links in which the referent participates. // If isDestroyOwnedObjects is true, destroy all objects owned by the referent via composition links. // Destroy the referent object. DestroyObjectAction action = (DestroyObjectAction)(this.node); Value value = this.takeTokens(action.target).getValue(0); this.destroyObject(value, action.isDestroyLinks, action.isDestroyOwnedObjects); Java // If the given value is a reference, then destroy the referenced object, per the given destroy action attribute values. // Debug.println("[destroyObject] object = " + value.objectId()); if (value instanceof Reference) { Reference reference = (Reference)value; if (isDestroyLinks | isDestroyOwnedObjects) { Debug.println("[destroyObject] Destroying links..."); ExtensionalValueList extensionalValues = this.getExecutionLocus().extensionalValues; for (int i = 0; i < extensionalValues.size(); i++) { ExtensionalValue extensionalValue = extensionalValues.getValue(i); if (extensionalValue instanceof Link) { Link link = (Link)extensionalValue; if (this.valueParticipatesInLink(reference, link)) { if (isDestroyLinks | this.objectIsComposite(reference, link)) { // Debug.println("[destroyObject] Destroying link " + link.objectId()); link.destroy(); } } } } } if (isDestroyOwnedObjects) { Debug.println("[destroyObject] Destroying owned objects..."); FeatureValueList objectFeatureValues = reference.getFeatureValues(); for (int i = 0; i < objectFeatureValues.size(); i++) { FeatureValue featureValue = objectFeatureValues.getValue(i); if (((Property)featureValue.feature).aggregation == AggregationKind.composite) { ValueList values = featureValue.values; for (int j = 0; j < values.size(); j++) { Value ownedValue = values.getValue(j); this.destroyObject(ownedValue, isDestroyLinks, isDestroyOwnedObjects); } } } } reference.destroy(); } Java // Test whether the given reference participates in the given link as a composite. FeatureValueList linkFeatureValues = link.getFeatureValues(); boolean isComposite = false; int i = 1; while (!isComposite & i <= linkFeatureValues.size()) { FeatureValue featureValue = linkFeatureValues.getValue(i-1); if (!featureValue.values.getValue(0).equals(reference) & ((Property)featureValue.feature).aggregation == AggregationKind.composite) { isComposite = true; } i = i + 1; } return isComposite; A create link action activation is a write link action activation for a create link action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // If the association has any unique ends, then destroy an existing link // that matches all ends of the link being created. // Get the extent at the current execution locus of the association for which a link is being created. // Destroy all links that have a value for any end for which isReplaceAll is true. // Create a new link for the association, at the current locus, with the given end data values, // inserted at the given insertAt position (for ordered ends). CreateLinkAction action = (CreateLinkAction)(this.node); LinkEndCreationDataList endDataList = action.endData; Association linkAssociation = this.getAssociation(); ExtensionalValueList extent = this.getExecutionLocus().getExtent(linkAssociation); boolean unique = false; for (int i = 0; i < endDataList.size(); i++) { if (endDataList.getValue(i).end.multiplicityElement.isUnique) { unique = true; } } for (int i = 0; i < extent.size(); i++) { ExtensionalValue value = extent.getValue(i); Link link = (Link) value; boolean match = true; boolean destroy = false; int j = 1; while (j <= endDataList.size()) { LinkEndCreationData endData = endDataList.getValue(j - 1); if (this.endMatchesEndData(link, endData)) { if (endData.isReplaceAll) { destroy = true; } } else { match = false; } j = j + 1; } if (destroy | unique & match ) { link.destroy(); } } Link newLink = new Link(); newLink.type = linkAssociation; for (int i = 0; i < endDataList.size(); i++) { LinkEndCreationData endData = endDataList.getValue(i); int insertAt = 0; if (endData.insertAt != null) { insertAt = ((UnlimitedNaturalValue) (this .takeTokens(endData.insertAt).getValue(0))).value.naturalValue; } newLink.setFeatureValue(endData.end, this.takeTokens(endData.value), insertAt); } newLink.addTo(this.getExecutionLocus()); A create object action activation is an action activation for a create object action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Create an object with the given classifier (which must be a class) as its type, at the same locus as the action activation. // Place a reference to the object on the result pin of the action. CreateObjectAction action = (CreateObjectAction)(this.node); Reference reference = new Reference(); reference.referent = this.getExecutionLocus().instantiate((Class_)(action.classifier)); this.putToken(action.result, reference); A clear association action activation is an action activation for a clear association action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the extent, at the current execution locus, of the given association. // Read the object input pin. Destroy all links in which the object participates. ClearAssociationAction action = (ClearAssociationAction)(this.node); ExtensionalValueList extent = this.getExecutionLocus().getExtent(action.association); Value objectValue = this.takeTokens(action.object).getValue(0); for (int i = 0; i < extent.size(); i++) { Link link = (Link)(extent.getValue(i)); if (this.valueParticipatesInLink(objectValue, link)) { link.destroy(); } } A clear structural feature action activation is a structural feature action activation for a clear structural feature action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Get the value of the object input pin. // If the given feature is an association end, then // destroy all links that have the object input on the opposite end. // Otherwise, if the object input is a structured value, then // set the appropriate feature of the input value to be empty. ClearStructuralFeatureAction action = (ClearStructuralFeatureAction)(this.node); StructuralFeature feature = action.structuralFeature; Association association = this.getAssociation(feature); Value value = this.takeTokens(action.object).getValue(0); if (association != null) { LinkList links = this.getMatchingLinks(association, feature, value); for (int i = 0; i < links.size(); i++) { Link link = links.getValue(i); link.destroy(); } } else if (value instanceof StructuredValue) { // If the value is a data value, then it must be copied before // any change is made. if (!(value instanceof Reference)) { value = value.copy(); } ((StructuredValue)value).setFeatureValue(action.structuralFeature, new ValueList(), 0); } if (action.result != null) { this.putToken(action.result, value); } import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.LociL1.*; An add structural feature action value activation is a write structural feature action activation for an add structural feature value action. Java // Get the values of the object and value input pins. // If the given feature is an association end, then create a link between the object and value inputs. // Otherwise, if the object input is a structural value, then add a value to the values for the feature. // If isReplaceAll is true, first remove all current matching links or feature values. // If isReplaceAll is false and there is an insertAt pin, insert the value at the appropriate position. AddStructuralFeatureValueAction action = (AddStructuralFeatureValueAction)(this.node); StructuralFeature feature = action.structuralFeature; Association association = this.getAssociation(feature); Value value = this.takeTokens(action.object).getValue(0); ValueList inputValues = this.takeTokens(action.value); // NOTE: Multiplicity of the value input pin is required to be 1..1. Value inputValue = inputValues.getValue(0); int insertAt = 0; if (action.insertAt != null) { insertAt = ((UnlimitedNaturalValue)this.takeTokens(action.insertAt).getValue(0)).value.naturalValue; } if (association != null) { LinkList links = this.getMatchingLinks(association, feature, value); Property oppositeEnd = this.getOppositeEnd(association, feature); int position = 0; if (oppositeEnd.multiplicityElement.isOrdered) { position = this.getMatchingLinks(association, oppositeEnd, inputValue).size() + 1; } if (action.isReplaceAll) { for (int i = 0; i < links.size(); i++) { Link link = links.getValue(i); link.destroy(); } } else if (feature.multiplicityElement.isUnique) { int i = 1; boolean destroyed = false; while (!destroyed & i <= links.size()) { Link link = links.getValue(i - 1); FeatureValue featureValue = link.getFeatureValue(feature); if (featureValue.values.getValue(0).equals(inputValue)) { position = link.getFeatureValue(oppositeEnd).position; link.destroy(); destroyed = true; } i = i + 1; } } Link newLink = new Link(); newLink.type = association; newLink.setFeatureValue(feature, inputValues, insertAt); ValueList oppositeValues = new ValueList(); oppositeValues.addValue(value); newLink.setFeatureValue(oppositeEnd, oppositeValues, position); newLink.addTo(this.getExecutionLocus()); } else if (value instanceof StructuredValue) { // If the value is a data value, then it must be copied before // any change is made. if (!(value instanceof Reference)) { value = value.copy(); } StructuredValue structuredValue = (StructuredValue)value; if (action.isReplaceAll) { structuredValue.setFeatureValue(feature, inputValues, 0); } else { FeatureValue featureValue = structuredValue.getFeatureValue(feature); if (featureValue.values.size() > 0 & insertAt == 0 ) { // *** If there is no insertAt pin, then the structural feature must be unordered, and the insertion position is immaterial. *** insertAt = ((ChoiceStrategy)this.getExecutionLocus().factory.getStrategy("choice")).choose(featureValue.values.size()); } if (feature.multiplicityElement.isUnique) { // Remove any existing value that duplicates the input value int j = position(inputValue, featureValue.values, 1); if (j > 0) { featureValue.values.remove(j-1); } } if (insertAt <= 0) { // Note: insertAt = -1 indicates an unlimited value of "*" featureValue.values.addValue(inputValue); } else { featureValue.values.addValue(insertAt - 1, inputValue); } } } if (action.result != null) { this.putToken(action.result, value); } A start classifier behavior action activation is an action activation for a start classifier behavior action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; Java // Get the value on the object input pin. If it is not a reference, then do nothing. // Start the classifier behavior of the referent object for the classifier given as the type of the object input pin. // If the object input pin has no type, then start the classifier behaviors of all types of the referent object. [The required behavior in this case is not clear from the spec.] StartClassifierBehaviorAction action = (StartClassifierBehaviorAction)(this.node); Value object = this.takeTokens(action.object).getValue(0); if (object instanceof Reference) { ((Reference)object).startBehavior((Class_)(action.object.typedElement.type), new ParameterValueList()); } A start behavior action activation is an action activation for a start behavior action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; Java // Get the value on the object input pin. If it is not a reference, then do nothing. // Start the behavior of the referent object for the classifier given as the type of the object input pin, with parameter values taken from the argument input pins. // If the object input pin has no type, then start the classifier behaviors of all types of the referent object. StartObjectBehaviorAction action = (StartObjectBehaviorAction)(this.node); Value object = this.takeTokens(action.object).getValue(0); if (object instanceof Reference) { Class_ type = (Class_)(action.object.typedElement.type); InputPinList argumentPins = action.argument; ParameterValueList inputs = new ParameterValueList(); if (type != null) { Behavior behavior; if (type instanceof Behavior) { behavior = (Behavior)type; } else { behavior = type.classifierBehavior; } if (behavior != null) { ParameterList parameters = behavior.ownedParameter; int pinNumber = 1; int i = 1; while (i <= parameters.size()) { Parameter parameter = parameters.getValue(i-1); int j = pinNumber; if (parameter.direction == ParameterDirectionKind.in | parameter.direction == ParameterDirectionKind.inout) { ParameterValue parameterValue = new ParameterValue(); parameterValue.parameter = parameter; parameterValue.values = this.takeTokens(argumentPins.getValue(j-1)); inputs.addValue(parameterValue); j = j + 1; } pinNumber = j; i = i + 1; } } } ((Reference)object).startBehavior(type, inputs); } A reduce action activation is an action activation for a reduce action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; The current execution of the reducer behavior. Java // Get the values of the collection input pin. // If the input pin has no values, then do nothing. Otherwise, do the following. // Repeatedly invoke the reducer behavior on successive pairs to reduce the collection to a single value, and place that value on the result pin. // To invoke the reducer behavior, compile it to create an execution, make the execution the current execution, place the appropriate values on its input parameters, and execute it. ReduceAction action = (ReduceAction)(this.node); ValueList values = this.takeTokens(action.collection); if (values.size() > 0) { ParameterList parameters = action.reducer.ownedParameter; Parameter input1 = null; Parameter input2 = null; Parameter output = null; int i = 1; while (i <= parameters.size()) { Parameter parameter = parameters.getValue(i-1); if (parameter.direction == ParameterDirectionKind.in) { if (input1 == null) { input1 = parameter; } else { input2 = parameter; } } else if (parameter.direction == ParameterDirectionKind.out | parameter.direction == ParameterDirectionKind.return_) { output = parameter; } i = i + 1; } ParameterValue parameterValue1 = new ParameterValue(); parameterValue1.parameter = input1; parameterValue1.values = new ValueList(); parameterValue1.values.addValue(values.getValue(0)); int j = 2; while (j <= values.size()) { this.currentExecution = this.getExecutionLocus().factory.createExecution(action.reducer, this.getExecutionContext()); this.currentExecution.setParameterValue(parameterValue1); ParameterValue parameterValue2 = new ParameterValue(); parameterValue2.parameter = input2; parameterValue2.values = new ValueList(); parameterValue2.values.addValue(values.getValue(j-1)); this.currentExecution.setParameterValue(parameterValue2); this.currentExecution.execute(); parameterValue1.values = this.currentExecution.getParameterValue(output).values; j = j + 1; if (parameterValue1.values.isEmpty() & j <= values.size()) { parameterValue1.values.add(values.getValue(j - 1)); j = j + 1; } } this.putTokens(action.result, parameterValue1.values); } Java // If there is a current execution, terminate it. Then terminate self. if (this.currentExecution != null) { this.currentExecution.terminate(); } super.terminate(); A read-is-classified object activation is an action activation for a read-is-classified object action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; Java // Get the value on the object input pin and determine if it is classified by the classifier specified in the action. // If the isDirect attribute of the action is false, then place true on the result output pin if the input object has the specified classifier or of one its (direct or indirect) descendants as a type. // If the isDirect attribute of the action is true, then place true on the result output pin if the input object has the specified classifier as a type. // Otherwise place false on the result output pin. ReadIsClassifiedObjectAction action = (ReadIsClassifiedObjectAction)(this.node); Value input = this.takeTokens(action.object).getValue(0); ClassifierList types = input.getTypes(); boolean result = false; int i = 1; while (!result & i <= types.size()) { Classifier type = types.getValue(i-1); if (type == action.classifier) { result = true; } else if (!action.isDirect) { result = this.checkAllParents(type, action.classifier); } i = i + 1; } ValueList values = new ValueList(); values.addValue(this.makeBooleanValue(result)); this.putTokens(action.result, values); Java // Check if the given classifier matches any of the direct or indirect ancestors of a given type. ClassifierList directParents = type.general; boolean matched = false; int i = 1; while (!matched & i <= directParents.size()) { Classifier directParent = directParents.getValue(i-1); if (directParent == classifier) { matched = true; } else { matched = this.checkAllParents(directParent, classifier); } i = i + 1; } return matched; A reclassify object activation is an action activation for a reclassify object action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; Java // Get the value of the object input pin. If it is not a reference, then do nothing. Otherwise, do the following. // Remove all types from the referent object that are in the set of old classifiers but not the set of new classifiers (or just all types that are not new classifiers, if isReplaceAll is true). // Remove the feature values from the referent object for all classifiers that are removed. // Add all new classifiers as types of the referent object that are not already types. // Add (empty) feature values to the referent object for the structural features of all added classifiers. ReclassifyObjectAction action = (ReclassifyObjectAction)(this.node); ClassifierList newClassifiers = action.newClassifier; ClassifierList oldClassifiers = action.oldClassifier; Value input = this.takeTokens(action.object).getValue(0); if (input instanceof Reference) { Object_ object = ((Reference)input).referent; int i = 1; while (i <= object.types.size()) { Class_ type = object.types.getValue(i-1); boolean toBeRemoved = true; int j = 1; while (toBeRemoved & j <= newClassifiers.size()) { toBeRemoved = (type != newClassifiers.getValue(j-1)); j = j + 1; } if (toBeRemoved & !action.isReplaceAll) { boolean notInOld = true; int k = 1; while (notInOld & k <= oldClassifiers.size()) { notInOld = (type != oldClassifiers.getValue(k-1)); k = k + 1; } toBeRemoved = !notInOld; } if (toBeRemoved) { object.types.removeValue(i-1); object.removeFeatureValues(type); } else { i = i + 1; } } for (int n = 0; n < newClassifiers.size(); n++) { Classifier classifier = newClassifiers.getValue(n); boolean toBeAdded = true; int j = 1; while (toBeAdded & j <= object.types.size()) { toBeAdded = (classifier != object.types.getValue(j-1)); j = j + 1; } if (toBeAdded) { object.types.addValue((Class_)classifier); NamedElementList members = classifier.member; for (int k = 0; k < members.size(); k++) { NamedElement member = members.getValue(k); if (member instanceof StructuralFeature) { object.setFeatureValue((StructuralFeature)member, new ValueList(), 0); } } } } } A read extent action activation is an action activation for a read extent action. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; Java // Get the extent, at the current execution locus, of the classifier (which must be a class) identified in the action. // Place references to the resulting set of objects on the result pin. ReadExtentAction action = (ReadExtentAction)(this.node); ExtensionalValueList objects = this.getExecutionLocus().getExtent(action.classifier); // Debug.println("[doAction] " + action.classifier.name + " has " + objects.size() + " instance(s)."); ValueList references = new ValueList(); for (int i = 0; i < objects.size(); i++) { Value object = objects.getValue(i); Reference reference = new Reference(); reference.referent = (Object_)object; references.addValue(reference); } this.putTokens(action.result, references); An accept event action activation is an action activation for an accept event action. import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; If the accept event action activation is waiting for an event, then this is the accepter it has registered for the event. Java // Create an event accepter and initialize waiting to false. super.run(); this.eventAccepter = new AcceptEventActionEventAccepter(); this.eventAccepter.actionActivation = this; this.waiting = false; Java // Register the event accepter for this accept event action activation with the context object of the enclosing activity execution // and wait for an event to be accepted. Debug.println("[fire] Action " + this.node.name + "..."); this.getExecutionContext().register(this.eventAccepter); this.waiting = true; this.firing = false; this.suspend(); Java // An accept event action activiation is ready to fire only if it is not already waiting for an event. boolean ready; if (this.waiting) { ready = false; } else { ready = super.isReady(); } return ready; Java // Do nothing. [This will never be called.] return; Java // Accept a signal occurance for the given signal instance. // If the action does not unmarshall, then place the signal instance on the result pin, if any. // If the action does unmarshall, then get the feature values of the signal instance, and place the values for each feature on the corresponding output pin. // Concurrently fire all output pins while offering a single control token. // If there are no incoming edges, then re-register this accept event action execution with the context object. AcceptEventAction action = (AcceptEventAction)(this.node); OutputPinList resultPins = action.result; Debug.println("[accept] action = " + action.name + ", signalinstance = " + signalInstance); if (this.running) { if (!action.isUnmarshall) { ValueList result = new ValueList(); result.addValue(signalInstance); if (resultPins.size() > 0) { this.putTokens(resultPins.getValue(0), result); } } else { FeatureValueList featureValues = signalInstance.getFeatureValues(); for (int i = 0; i < featureValues.size(); i++) { FeatureValue featureValue = featureValues.getValue(i); OutputPin resultPin = resultPins.getValue(i); this.putTokens(resultPin, featureValue.values); } } this.sendOffers(); this.waiting = false; Debug.println("[fire] Checking if " + this.node.name + " should fire again..."); this.receiveOffer(); this.resume(); } Java // Return true if the given signal instance matches a trigger of the accept action of this activation. AcceptEventAction action = (AcceptEventAction)(this.node); TriggerList triggers = action.trigger; Signal signal = signalInstance.type; boolean matches = false; int i = 1; while (!matches & i <= triggers.size()) { matches = ((SignalEvent)(triggers.getValue(i-1).event)).signal == signal; i = i + 1; } return matches; Java // Terminate this action and unregister its event accepter. super.terminate(); if (this.waiting) { this.getExecutionContext().unregister(this.eventAccepter); this.waiting = false; } An accept event action event accepter handles signal reception events on the behalf of a specific accept event action activation. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.*; The accept event action activation on behalf of which this event accepter is waiting. Java // Accept a signal occurance for the given signal instance. // Forward the signal occuranceto the action activation. this.actionActivation.accept(signalInstance); Java // Return true if the given signal instance matches a trigger of the accept action of the action activation. return this.actionActivation.match(signalInstance); Accept a signal occurance for the given signal instance. Determine if the given signal instance matches a trigger of the accept action of the action activation. A structured activity node activation is an action activation for an action that is a structured activity node. import java.util.*; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The group of activations of the activity nodes contained in the structured activity node. Java // If the structured activity node has mustIsolate=true, then carry out its behavior with isolation. // Otherwise just activate it normally. if (((StructuredActivityNode)(this.node)).mustIsolate) { _beginIsolation(); this.doStructuredActivity(); _endIsolation(); } else { this.doStructuredActivity(); } Java // Run all activations of contained nodes. When this is complete, return. // (This is the default behavior for a structured activity node used simply as a group. It is overridden for the execution of conditional and loop nodes.) Action action = (Action)(this.node); // *** Concurrently send offers from all input pins. *** InputPinList inputPins = action.input; for (Iterator i = inputPins.iterator(); i.hasNext();) { InputPin inputPin = (InputPin)i.next(); PinActivation pinActivation = this.getPinActivation(inputPin); pinActivation.sendUnofferedTokens(); } this.activationGroup.run(this.activationGroup.nodeActivations); Java // Terminate the execution of all contained node activations (which // completes the performance of the structured activity node // activation), and then terminate this node itself. this.terminateAll(); super.terminate(); Java // If this structured activity node activation is not for the given node, then check if there is an activation for the node in the activation group. ActivityNodeActivation thisActivation = super.getNodeActivation(node); ActivityNodeActivation activation = null; if (thisActivation != null) { activation = thisActivation; } else if (this.activationGroup != null) { activation = this.activationGroup.getNodeActivation(node); } return activation; Java // Return an activity node list containing the given list of executable nodes // and any pins that they own. ActivityNodeList activityNodes = new ActivityNodeList(); for (int i = 0; i < nodes.size(); i++) { ActivityNode node = nodes.getValue(i); activityNodes.addValue(node); if (node instanceof Action) { Action action = (Action)node; InputPinList inputPins = action.input; for (int j = 0; j < inputPins.size(); j++) { InputPin inputPin = inputPins.getValue(j); activityNodes.addValue(inputPin); } OutputPinList outputPins = action.output; for (int j = 0; j < outputPins.size(); j++) { OutputPin outputPin = outputPins.getValue(j); activityNodes.addValue(outputPin); } } } return activityNodes; Java // Return the values of the tokens on the pin activation corresponding to the given pin in the internal activation group for this node activation. PinActivation pinActivation = (PinActivation)(this.activationGroup.getNodeActivation(pin)); TokenList tokens = pinActivation.getTokens(); ValueList values = new ValueList(); for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); Value value = ((ObjectToken)token).value; if (value != null) { values.addValue(value); } } return values; Java // Place tokens for the given values on the pin activation corresponding to the given output pin on the internal activation group for this node activation. PinActivation pinActivation = (PinActivation)(this.activationGroup.getNodeActivation(pin)); for (int i = 0; i < values.size(); i++) { Value value = values.getValue(i); ObjectToken token = new ObjectToken(); token.value = value; pinActivation.addToken(token); } Java // Create an activation group and create node activations for all the nodes within the structured activity node. super.createNodeActivations(); this.activationGroup = new ActivityNodeActivationGroup(); this.activationGroup.containingNodeActivation = this; this.activationGroup.createNodeActivations(((StructuredActivityNode)(this.node)).node); Java // Create instances for all edges owned by this node. this.activationGroup.createEdgeInstances(((StructuredActivityNode)(this.node)).edge); Java // Returns true if this node is either the source for the given // edgeInstance itself or if it contains the source in its // activation group. boolean isSource = super.isSourceFor(edgeInstance); if (!isSource) { isSource = this.activationGroup.hasSourceFor(edgeInstance); } return isSource; Java // Terminate the execution of all contained node activations (which // completes the performance of the structured activity node // activation). this.activationGroup.terminateAll(); Java // Check if the activation group for this node is suspended. return this.activationGroup.isSuspended(); Java // Only actually complete this structured activity node if it is not // suspended. TokenList incomingTokens = new TokenList(); if (!this.isSuspended()) { incomingTokens = super.completeAction(); } return incomingTokens; Java // When this structured activity node is resumed after being suspended, // then complete its prior firing and, if there are more incoming // tokens, fire it again. If, after that, the node is not suspended, // then finish its resumption. TokenList incomingTokens = super.completeAction(); if (incomingTokens.size() > 0) { this.fire(incomingTokens); } if (!this.isSuspended()) { super.resume(); } A loop node activation is a structured activity node activation for a node that is a loop node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Set the initial values for the body outputs to the values of the loop variable input pins. // If isTestedFirst is true, then repeatedly run the test part and the body part of the loop, copying values from the body outputs to the loop variables. // If isTestedFirst is false, then repeatedly run the body part and the test part of the loop, copying values from the body outputs to the loop variables. // When the test fails, copy the values of the body outputs to the loop outputs. // [Note: The body outputs are used for the loop outputs, rather than the loop variables, since values on the loop variables may be consumed when running the test for the last time.] LoopNode loopNode = (LoopNode)(this.node); InputPinList loopVariableInputs = loopNode.loopVariableInput; OutputPinList loopVariables = loopNode.loopVariable; OutputPinList resultPins = loopNode.result; ValuesList bodyOutputLists = this.bodyOutputLists; for (int i = 0; i < loopVariableInputs.size(); i++) { InputPin loopVariableInput = loopVariableInputs.getValue(i); Values bodyOutputList = new Values(); bodyOutputList.values = this.takeTokens(loopVariableInput); this.bodyOutputLists.addValue(bodyOutputList); } this.doLoop(true); Java // Run the test part of the loop node for this node activation. // Return the value on the decider pin. Debug.println("[runTest] Running test..."); LoopNode loopNode = (LoopNode)(this.node); this.activationGroup.runNodes(this.makeActivityNodeList(loopNode.test)); ValueList values = this.getPinValues(loopNode.decider); // If there is no decider value, treat it as false. boolean decision = false; if (values.size() > 0) { decision = ((BooleanValue)(values.getValue(0))).value; } Debug.println("[runTest] " + (decision? "Test succeeded.": "Test failed.")); return decision; Java // Run the body part of the loop node for this node activation and save the body outputs. Debug.println("[runBody] Running body..."); LoopNode loopNode = (LoopNode)this.node; this.activationGroup.runNodes(this.makeActivityNodeList(loopNode.bodyPart)); if (!this.isSuspended()) { this.saveBodyOutputs(); } Java // Run the loop variable pins of the loop node for this node activation. this.activationGroup.runNodes(this.makeLoopVariableList()); Java // In addition to creating activations for contained nodes, create activations for any loop variables. super.createNodeActivations(); this.activationGroup.createNodeActivations(this.makeLoopVariableList()); Java // Return an activity node list containing the loop variable pins for the loop node of this activation. LoopNode loopNode = (LoopNode)(this.node); ActivityNodeList nodes = new ActivityNodeList(); OutputPinList loopVariables = loopNode.loopVariable; for (int i = 0; i < loopVariables.size(); i++) { OutputPin loopVariable = loopVariables.getValue(i); nodes.addValue(loopVariable); } return nodes; Java // Copy the values of the body outputs to the loop outputs, and then // terminate all activations in the loop. OutputPinList resultPins = ((LoopNode)this.node).result; for (int i = 0; i < bodyOutputLists.size(); i++) { Values bodyOutputList = bodyOutputLists.getValue(i); OutputPin resultPin = resultPins.getValue(i); this.putTokens(resultPin, bodyOutputList.values); } super.terminateAll(); Java // If isTestedFirst is true, then repeatedly run the test part and the // body part of the loop, copying values from the body outputs to the // loop variables. // If isTestedFirst is false, then repeatedly run the body part and the // test part of the loop, copying values from the body outputs to the // loop variables. LoopNode loopNode = (LoopNode) (this.node); OutputPinList loopVariables = loopNode.loopVariable; OutputPinList resultPins = loopNode.result; while (continuing) { // Set loop variable values this.runLoopVariables(); for (int i = 0; i < loopVariables.size(); i++) { OutputPin loopVariable = loopVariables.getValue(i); Values bodyOutputList = bodyOutputLists.getValue(i); ValueList values = bodyOutputList.values; this.putPinValues(loopVariable, values); ((OutputPinActivation) this.activationGroup .getNodeActivation(loopVariable)).sendUnofferedTokens(); } // Run all the non-executable, non-pin nodes in the conditional // node. ActivityNodeActivationList nodeActivations = this.activationGroup.nodeActivations; ActivityNodeActivationList nonExecutableNodeActivations = new ActivityNodeActivationList(); for (int i = 0; i < nodeActivations.size(); i++) { ActivityNodeActivation nodeActivation = nodeActivations .getValue(i); if (!(nodeActivation.node instanceof ExecutableNode | nodeActivation.node instanceof Pin)) { nonExecutableNodeActivations.addValue(nodeActivation); } } this.activationGroup.run(nonExecutableNodeActivations); // Run the loop if (loopNode.isTestedFirst) { continuing = this.runTest(); if (continuing) { this.runBody(); } } else { this.runBody(); if (this.isRunning() & !this.isSuspended()) { continuing = this.runTest(); } } if (this.isRunning() && !this.isSuspended()) { this.activationGroup.terminateAll(); } else { continuing = false; } Debug.println("[doStructuredActivity] " + (continuing? "Continuing." : this.isSuspended()? "Suspended": "Done.")); } if (this.isRunning() && !this.isSuspended()) { for (int i = 0; i < bodyOutputLists.size(); i++) { Values bodyOutputList = bodyOutputLists.getValue(i); OutputPin resultPin = resultPins.getValue(i); this.putTokens(resultPin, bodyOutputList.values); } } Java // Save the body outputs for use in the next iteration. LoopNode loopNode = (LoopNode) this.node; OutputPinList bodyOutputs = loopNode.bodyOutput; ValuesList bodyOutputLists = this.bodyOutputLists; for (int i = 0; i < bodyOutputs.size(); i++) { OutputPin bodyOutput = bodyOutputs.getValue(i); Values bodyOutputList = bodyOutputLists.getValue(i); bodyOutputList.values = this.getPinValues(bodyOutput); } Java // When this loop node is resumed after being suspended, continue with // its next iteration (if any). Once the loop has completed execution // without being suspended again, complete the action. LoopNode loopNode = (LoopNode) (this.node); this.saveBodyOutputs(); if (loopNode.mustIsolate) { _beginIsolation(); this.continueLoop(); _endIsolation(); } else { this.continueLoop(); } if (this.isSuspended()) { // NOTE: If the subsequent iteration of the loop suspends it again, // then it is necessary to remove the previous suspension from the // containing activity node activation group. this.group.resume(this); } else { super.resume(); } Java // Continue the loop node when it is resumed after being suspended. If // isTestedFirst is true, then continue executing the loop. If // isTestedFirst is false, then run the test to determine whether // the loop should be continued or completed. // [Note that this presumes that an accept event action is not allowed // in the test part of a loop node.] LoopNode loopNode = (LoopNode) (this.node); boolean continuing = true; if (!loopNode.isTestedFirst) { continuing = this.runTest(); } if (this.isRunning()) { this.activationGroup.terminateAll(); this.doLoop(continuing); } A conditional node activation is a structured activity node activation for a node that is a conditional node. import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.LociL1.*; The activations for each clause in the conditional node for this node activation. The set of clauses which meet the conditions to have their bodies activated. The clause chosen from the set of selectedClauses to actually be executed. Java // Run all the non-executable, non-pin nodes in the conditional node. // Activate all clauses in the conditional node and pass control to those that are ready (i.e., have no predecessors). // If one or more clauses have succeeded in being selected, choose one non-deterministically and run its body, then copy the outputs of that clause to the output pins of the node. ConditionalNode node = (ConditionalNode)(this.node); ActivityNodeActivationList nodeActivations = this.activationGroup.nodeActivations; ActivityNodeActivationList nonExecutableNodeActivations = new ActivityNodeActivationList(); for (int i = 0; i < nodeActivations.size(); i++) { ActivityNodeActivation nodeActivation = nodeActivations.getValue(i); if (!(nodeActivation.node instanceof ExecutableNode | nodeActivation.node instanceof Pin)) { nonExecutableNodeActivations.addValue(nodeActivation); } } this.activationGroup.run(nonExecutableNodeActivations); this.clauseActivations.clear(); ClauseList clauses = node.clause; for (int i = 0; i < clauses.size(); i++) { Clause clause = clauses.getValue(i); ClauseActivation clauseActivation = new ClauseActivation(); clauseActivation.clause = clause; clauseActivation.conditionalNodeActivation = this; this.clauseActivations.addValue(clauseActivation); } this.selectedClauses.clear(); ClauseActivationList readyClauseActivations = new ClauseActivationList(); for (int i = 0; i < this.clauseActivations.size(); i++) { ClauseActivation clauseActivation = this.clauseActivations.getValue(i); Debug.println("[doStructuredActivity] clauseActivations[" + i + "] = " + clauseActivation); if (clauseActivation.isReady()) { Debug.println("[doStructuredActivity] Clause activation is ready."); readyClauseActivations.addValue(clauseActivation); } } // *** Give control to all ready clauses concurrently. *** for (Iterator i = readyClauseActivations.iterator(); i.hasNext() ;) { ClauseActivation clauseActivation = (ClauseActivation)i.next(); Debug.println("[doStructuredActivity] Giving control to " + clauseActivation + "..."); clauseActivation.receiveControl(); } this.selectedClause = null; if (this.selectedClauses.size() > 0 & this.isRunning()) { Debug.println("[doStructuredActivity] " + this.selectedClauses.size() + " clause(s) selected."); // *** If multiple clauses are selected, choose one non-deterministically. *** int i = ((ChoiceStrategy)this.getExecutionLocus().factory.getStrategy("choice")).choose(this.selectedClauses.size()); this.selectedClause = this.selectedClauses.getValue(i-1); Debug.println("[doStructuredActivity] Running selectedClauses[" + i + "] = " + this.selectedClause); for (int j = 0; j < clauses.size(); j++) { Clause clause = clauses.getValue(j); if (clause != selectedClause) { ExecutableNodeList testNodes = clause.test; for (int k = 0; k < testNodes.size(); k++) { ExecutableNode testNode = testNodes.getValue(k); this.activationGroup.getNodeActivation(testNode).terminate(); } } } this.activationGroup.runNodes(this.makeActivityNodeList(this.selectedClause.body)); } Java // Get the clause activation corresponding to the given clause. // Debug.println("[getClauseActivation] clause = " + clause); ClauseActivation selectedClauseActivation = null; int i = 1; while ((selectedClauseActivation == null) & i <= this.clauseActivations.size()) { ClauseActivation clauseActivation = this.clauseActivations.getValue(i-1); // Debug.println("[getClauseActivations] clauseActivations[" + i + "].clause = " + clauseActivation.clause); if (clauseActivation.clause == clause) { selectedClauseActivation = clauseActivation; } i = i + 1; } return selectedClauseActivation; Java // Run the test for the given clause. if (this.isRunning()) { this.activationGroup.runNodes(this.makeActivityNodeList(clause.test)); } Java // Add the clause to the list of selected clauses. this.selectedClauses.addValue(clause); Java // Complete the activation of the body of a conditional note by // copying the outputs of the selected clause (if any) to the output // pins of the node and terminating the activation of all nested nodes. if (this.selectedClause != null) { ConditionalNode node = (ConditionalNode) (this.node); OutputPinList resultPins = node.result; OutputPinList bodyOutputPins = this.selectedClause.bodyOutput; for (int k = 0; k < resultPins.size(); k++) { OutputPin resultPin = resultPins.getValue(k); OutputPin bodyOutputPin = bodyOutputPins.getValue(k); this.putTokens(resultPin, this.getPinValues(bodyOutputPin)); } } this.activationGroup.terminateAll(); Java // Only complete the conditional node if it is not suspended. if (!this.isSuspended()) { completeBody(); } return super.completeAction(); Java // When this conditional node is resumed after being suspended, complete // its body and then resume it as a structured activity node. // [Note that this presumes that accept event actions are not allowed // in the test part of a clause of a conditional node.] completeBody(); super.resume(); A clause activation defines the behavior of a clause within the context of a specific activation of the conditional node containing the clause. import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The activation of the conditional node that contains the clause for this clause activation. Java // If all predecessors to the clause for this activation have run their tests and failed, then run the test for this clause. // If the test succeeds, then terminate any other clauses that may be running and run the body of this clause. // If the test fails, then pass control to successor clauses. Debug.println("[receiveControl] clauseActivation = " + this); if (this.isReady()) { Debug.println("[receiveControl] Running test..."); this.runTest(); BooleanValue decision = this.getDecision(); // Note that the decision may be null if the test was terminated before completion. if (decision != null) { if (decision.value == true) { Debug.println("[receiveControl] Test succeeded."); this.selectBody(); } else { Debug.println("[receiveControl] Test failed."); ClauseActivationList successors = this.getSuccessors(); // *** Give control to all successors concurrently. *** for (Iterator i = successors.iterator(); i.hasNext();) { ClauseActivation successor = (ClauseActivation)i.next(); successor.receiveControl(); } } } } Java // Test if all predecessors to this clause activation have failed. ClauseActivationList predecessors = this.getPredecessors(); boolean ready = true; int i = 1; while (ready & i <= predecessors.size()) { ClauseActivation predecessor = predecessors.getValue(i-1); BooleanValue decisionValue = predecessor.getDecision(); // Note that the decision will be null if the predecessor clause has not run yet. if (decisionValue == null) { ready = false; } else { ready = !decisionValue.value; } i = i + 1; } return ready; Java // Run the test of the clause for this clause activation. this.conditionalNodeActivation.runTest(this.clause); Java // Select the body of the clause for this clause activation. this.conditionalNodeActivation.selectBody(this.clause); Java // Get the value (if any) on the decider pin of the clause for this clause activation. ValueList deciderValues = this.conditionalNodeActivation.getPinValues(this.clause.decider); BooleanValue deciderValue = null; if (deciderValues.size() > 0) { deciderValue = (BooleanValue)(deciderValues.getValue(0)); } return deciderValue; Java // Return the clause activations for the predecessors of the clause for this clause activation. ClauseActivationList predecessors = new ClauseActivationList(); ClauseList predecessorClauses = this.clause.predecessorClause; for (int i = 0; i < predecessorClauses.size(); i++) { Clause predecessorClause = predecessorClauses.getValue(i); predecessors.addValue(this.conditionalNodeActivation.getClauseActivation(predecessorClause)); } return predecessors; Java // Return the clause activations for the successors of the clause for this clause activation. ClauseActivationList successors = new ClauseActivationList(); ClauseList successorClauses = this.clause.successorClause; for (int i = 0; i < successorClauses.size(); i++) { Clause successorClause = successorClauses.getValue(i); successors.addValue(this.conditionalNodeActivation.getClauseActivation(successorClause)); } return successors; A token is an individual element of data or control that may flow across an activity edge. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // if this token does not have any holder, make the given holder its holder. // Otherwise, remove this token from its holder and return a copy of it transfered to a new holder. Token token = this; if (this.holder != null) { this.withdraw(); token = this.copy(); } token.holder = holder; return token; Java // Remove this token from its holder, withdrawing any offers for it. if (!this.isWithdrawn()) { // Debug.println("[withdraw] Taking token with value = " + this.getValue()); this.holder.removeToken(this); this.holder = null; } Java // Test if this token has been withdrawn. return this.holder == null; Test if this token is equal to another token. // Make a copy of this token. Test whether this is a control token. Get the value associated with this token (if any). import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; An offer is a group of tokens offered together. The grouping of offered tokens into offers usually does not matter for how the tokens may be accepted. However, control and object tokens may become grouped together in the same offer due to a join node that has both incoming control and object flows. In this case, the control tokens are implicitly accepted once all the object tokens in the same offer have been accepted. Java // Return the number of values being offered on object tokens. // Remove any tokens that have already been withdrawn and don't include them in the count. this.removeWithdrawnTokens(); int count = 0; for (int i = 0; i < this.offeredTokens.size(); i++) { if (this.offeredTokens.getValue(i).getValue() != null) { count = count + 1; } } return count; Java // Get the offered tokens, removing any that have been withdrawn. this.removeWithdrawnTokens(); TokenList tokens = new TokenList(); TokenList offeredTokens = this.offeredTokens; for (int i = 0; i < this.offeredTokens.size() ; i++) { Token offeredToken = offeredTokens.getValue(i); // Debug.println("[getOfferedTokens] token value = " + offeredToken.getValue()); tokens.addValue(offeredToken); } return tokens; Java // Remove the given number of non-null object tokens from those in this offer. int n = count; int i = 1; while (n > 0) { if (this.offeredTokens.getValue(i-1).getValue() != null) { this.offeredTokens.removeValue(i-1); } else { i = i + 1; } n = n - 1; } Java // Remove any tokens that have already been consumed. TokenList offeredTokens = this.offeredTokens; int i = 1; while (i <= this.offeredTokens.size()) { if (this.offeredTokens.getValue(i-1).isWithdrawn()) { this.offeredTokens.remove(i-1); i = i - 1; } i = i + 1; } Java // Check whether this offer has any tokens that have not been withdrawn. this.removeWithdrawnTokens(); return this.offeredTokens.size() > 0; An object token represents the passing of data along an object flow edge. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The value carried by this token. A token may have no value, in which case it is a "null token". Java // Test if this object token is the same as the other token. return this == other; Java // Return a new object token with the same value as this token. // [Note: the holder of the copy is not set.] ObjectToken copy = new ObjectToken(); copy.value = this.value; return copy; Java // Return false for an object token. return false; Java // Return the value of this object token. return this.value; An object node activation is an activity node activation for a node that is an object node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The number of held tokens that have already been offered. Java // Initialize the offered token count to zero. super.run(); this.offeredTokenCount = 0; Java // If the set of tokens to be sent is empty, then offer a null token instead. // Otherwise, offer the given tokens as usual. if (tokens.size() == 0) { ObjectToken token = new ObjectToken(); token.holder = this; tokens.addValue(token); } super.sendOffers(tokens); Java // Remove any offered tokens and terminate. this.clearTokens(); super.terminate(); Java // Transfer the given token to be held by this node only if it is a non-null object token. // If it is a control token or a null token, consume it without holding it. if (token.getValue() == null) { token.withdraw(); } else { super.addToken(token); } Java // Remove the given token, if it is held by this node activation. int i = super.removeToken(token); if (i > 0 & i <= this.offeredTokenCount) { this.offeredTokenCount = this.offeredTokenCount - 1; } return i; Java // Remove all held tokens. super.clearTokens(); this.offeredTokenCount = 0; Java // Count the total number of non-null object tokens being offered to this node activation. int totalValueCount = 0; int i = 1; while (i <= this.incomingEdges.size()) { totalValueCount = totalValueCount + this.incomingEdges.getValue(i-1).countOfferedValues(); i = i + 1; } return totalValueCount; Java // Send offers over all outgoing edges, if there are any tokens to be offered. TokenList tokens = this.getUnofferedTokens(); this.offeredTokenCount = this.offeredTokenCount + tokens.size(); this.sendOffers(tokens); Java // Return the number of unoffered tokens that are to be offered next. // (By default, this is all unoffered tokens.) if (this.heldTokens.size() == 0) { this.offeredTokenCount = 0; } return this.heldTokens.size() - this.offeredTokenCount; Java // Get the next set of unoffered tokens to be offered and return it. // [Note: This effectively treats all object flows as if they have weight=*, rather than the weight=1 default in the current superstructure semantics.] TokenList tokens = new TokenList(); int i = 1; while (i <= this.countUnofferedTokens()) { tokens.addValue(this.heldTokens.getValue(this.offeredTokenCount + i - 1)); i = i + 1; } return tokens; Java // Take the next set of unoffered tokens to be offered from this node activation and return them. TokenList tokens = this.getUnofferedTokens(); for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); token.withdraw(); } return tokens; A merge node activation is a control node activation for a node that is a merge node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; A join node activation is a control node activation for a node that is a join node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Check that all incoming edges have sources that are offering tokens. boolean ready = true; int i = 1; while (ready & i <=this.incomingEdges.size()) { ready = this.incomingEdges.getValue(i-1).hasOffer(); i = i + 1; } return ready; A forked token is a proxy for a token that has been offered through a fork node. If the token is accepted through the fork node, then the original token is withdrawn from its holder, but the forked token remains held by the fork node activation until all outstanding offers on all outgoing edges are accepted. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The remaining number of outstanding offers for this token on outgoing edges of the fork node. Indicates whether withdraw() has been called on the base token. Java // Test if the base token is a control token. return this.baseToken.isControl(); Java // If the base token is not withdrawn, then withdraw it. // Decrement the remaining offers count. // When the remaining number of offers is zero, then remove this token from its holder. if (!this.baseTokenIsWithdrawn & !this.baseToken.isWithdrawn()) { this.baseToken.withdraw(); // NOTE: This keeps a base token that is a forked token from being // withdrawn more than once, since withdrawing a forked token may // not actually remove it from its fork node holder. this.baseTokenIsWithdrawn = true; } if (this.remainingOffersCount > 0) { this.remainingOffersCount = this.remainingOffersCount - 1; } if (this.remainingOffersCount == 0) { super.withdraw(); } Java // Return a copy of the base token. return this.baseToken.copy(); Java // Test if this token is equal to another token. return this == otherToken; Java // Return the value of the base token. return this.baseToken.getValue(); A fork node activation is a control node activation for a node that is a fork node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Create forked tokens for all incoming tokens and offer them on all outgoing edges. if (this.node == null) { Debug.println("[fire] Anonymous fork node."); } else { Debug.println("[fire] Fork node " + this.node.name + "..."); } ActivityEdgeInstanceList outgoingEdges = this.outgoingEdges; int outgoingEdgeCount = outgoingEdges.size(); TokenList forkedTokens = new TokenList(); for (int i = 0; i < incomingTokens.size(); i++) { Token token = incomingTokens.getValue(i); ForkedToken forkedToken = new ForkedToken(); forkedToken.baseToken = token; forkedToken.remainingOffersCount = outgoingEdgeCount; forkedToken.baseTokenIsWithdrawn = false; forkedTokens.addValue(forkedToken); } this.addTokens(forkedTokens); this.sendOffers(forkedTokens); Java // Remove any offered tokens and terminate. this.clearTokens(); super.terminate(); An initial node activation is a control node activation for a node that is an initial node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Create a single token and send offers for it. TokenList tokens = new TokenList(); tokens.addValue(new ControlToken()); this.addTokens(tokens); this.sendOffers(tokens); import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The current execution of the decision input behavior (if any). Java // Get the decision values and test them on each guard. // Forward the offer over the edges for which the test succeeds. Debug.println("[fire] Decision node " + this.node.name + "..."); //TokenList incomingTokens = this.takeOfferedTokens(); TokenList removedControlTokens = this.removeJoinedControlTokens(incomingTokens); ValueList decisionValues = this.getDecisionValues(incomingTokens); ActivityEdgeInstanceList outgoingEdges = this.outgoingEdges; for (int i = 0; i < outgoingEdges.size(); i++) { ActivityEdgeInstance edgeInstance = outgoingEdges.getValue(i); ValueSpecification guard = edgeInstance.edge.guard; TokenList offeredTokens = new TokenList(); for (int j = 0; j < incomingTokens.size(); j++) { Token incomingToken = incomingTokens.getValue(j); Value decisionValue = decisionValues.getValue(j); if (this.test(guard, decisionValue)) { offeredTokens.addValue(incomingToken); } } if (offeredTokens.size() > 0) { for (int j = 0; j < removedControlTokens.size(); j++) { Token removedControlToken = removedControlTokens.getValue(j); offeredTokens.addValue(removedControlToken); } edgeInstance.sendOffer(offeredTokens); } } Java // If there is neither a decision input flow nor a decision input behavior, then return the set of values from the incoming tokens. // [In this case, the single incoming edge must be an object flow.] // If there is a decision input flow, but no decision input behavior, then return a list of the decision input values equal in size to the number of incoming tokens. // If there is both a decision input flow and a decision input behavior, then execute the decision input behavior once for each incoming token and return the set of resulting values. // If the primary incoming edge is an object flow, then the value on each object token is passed to the decision input behavior, along with the decision input flow value, if any. // If the primary incoming edge is a control flow, then the decision input behavior only receives the decision input flow, if any. Value decisionInputValue = this.getDecisionInputFlowValue(); ValueList decisionValues = new ValueList(); for (int i = 0; i < incomingTokens.size(); i++) { Token incomingToken = incomingTokens.getValue(i); Value value = this.executeDecisionInputBehavior(incomingToken.getValue(), decisionInputValue); decisionValues.addValue(value); } // Debug.println("[getDecisionValues] " + decisionValues.size() + " decision value(s):"); for (int i = 0; i < decisionValues.size(); i++) { Value decisionValue = decisionValues.getValue(i); Debug.println("[getDecisionValues] decisionValues[" + i + "] = " + decisionValue); } return decisionValues; Java // Create the decision input execution from the decision input behavior. // If the behavior has input parameter(s), set the input parameter(s) of the execution to the given value(s). // Execute the decision input execution and then remove it. // Return the value of the output parameter of the execution. // If there is no decision input behavior, the decision input value is returned, if one is given, otherwise the input value is used as the decision value. Debug.println("[executeDecisionBehavior] inputValue = " + inputValue); Behavior decisionInputBehavior = ((DecisionNode)(this.node)).decisionInput; Value decisionInputResult = null; if (decisionInputBehavior == null) { if (decisionInputValue != null) { decisionInputResult = decisionInputValue; } else { decisionInputResult = inputValue; } } else { this.decisionInputExecution = this.getExecutionLocus().factory.createExecution(decisionInputBehavior, this.getExecutionContext()); int i = 1; int j = 0; while ((j == 0 | (j == 1 & decisionInputValue != null)) & i <= decisionInputBehavior.ownedParameter.size()) { Parameter parameter = decisionInputBehavior.ownedParameter.getValue(i-1); if (parameter.direction.equals(ParameterDirectionKind.in) | parameter.direction.equals(ParameterDirectionKind.inout)) { ParameterValue inputParameterValue = new ParameterValue(); inputParameterValue.parameter = parameter; j = j +1; if (j == 1 && inputValue != null) { inputParameterValue.values.addValue(inputValue); } else { inputParameterValue.values.addValue(decisionInputValue); } this.decisionInputExecution.setParameterValue(inputParameterValue); } i = i + 1; } this.decisionInputExecution.execute(); ParameterValueList outputParameterValues = this.decisionInputExecution.getOutputParameterValues(); decisionInputExecution.destroy(); decisionInputResult = outputParameterValues.getValue(0).values.getValue(0); } return decisionInputResult; Java // Terminate the decision input execution, if any, and then terminate this activation. if (this.decisionInputExecution != null) { this.decisionInputExecution.terminate(); } super.terminate(); Java // Check that all incoming edges have sources that are offering tokens. // [This should be at most two incoming edges, if there is a decision input flow.] int i = 1; boolean ready = true; while (ready & i <= this.incomingEdges.size()) { ready = this.incomingEdges.getValue(i-1).hasOffer(); i = i + 1; } return ready; Java // Get tokens from the incoming edge that is not the decision input flow. ObjectFlow decisionInputFlow = ((DecisionNode)(this.node)).decisionInputFlow; TokenList allTokens = new TokenList(); ActivityEdgeInstanceList incomingEdges = this.incomingEdges; for (int i = 0; i < incomingEdges.size(); i++) { ActivityEdgeInstance edgeInstance = incomingEdges.getValue(i); if (edgeInstance.edge != decisionInputFlow) { TokenList tokens = edgeInstance.takeOfferedTokens(); for (int j = 0; j < tokens.size(); j++) { allTokens.addValue(tokens.getValue(j)); } } } return allTokens; Java // Take the next token available on the decision input flow, if any, and return its value. ActivityEdgeInstance decisionInputFlowInstance = this.getDecisionInputFlowInstance(); Value value = null; if (decisionInputFlowInstance != null) { TokenList tokens = decisionInputFlowInstance.takeOfferedTokens(); if (tokens.size() > 0) { value = tokens.getValue(0).getValue(); } } return value; Java // Get the activity edge instance for the decision input flow, if any. ActivityEdge decisionInputFlow = ((DecisionNode)(this.node)).decisionInputFlow; ActivityEdgeInstance edgeInstance = null; if (decisionInputFlow != null) { int i = 1; while (edgeInstance == null & i <=this.incomingEdges.size()) { ActivityEdgeInstance incomingEdge = this.incomingEdges.getValue(i-1); if (incomingEdge.edge == decisionInputFlow) { edgeInstance = incomingEdge; } i = i + 1; } } return edgeInstance; Java // Test if the given value matches the guard. If there is no guard, return true. boolean guardResult = true; if (guard != null) { Value guardValue = this.getExecutionLocus().executor.evaluate(guard); guardResult = guardValue.equals(value); } return guardResult; Java // If the primary incoming edge is an object flow, then remove any control tokens from the incoming tokens and return them. // [Control tokens may effectively be offered on an object flow outgoing from a join node that has both control and object flows incoming.] TokenList removedControlTokens = new TokenList(); if (this.hasObjectFlowInput()) { int i = 1; while (i <= incomingTokens.size()) { Token token = incomingTokens.getValue(i-1); if (token.isControl()) { removedControlTokens.addValue(token); incomingTokens.removeValue(i-1); i = i - 1; } i = i + 1; } } return removedControlTokens; Java // Check that the primary incoming edge is an object flow. ActivityEdge decisionInputFlow = ((DecisionNode)(this.node)).decisionInputFlow; boolean isObjectFlow = false; int i = 1; while (!isObjectFlow & i <= this.incomingEdges.size()) { ActivityEdge edge = this.incomingEdges.getValue(i-1).edge; isObjectFlow = edge != decisionInputFlow & edge instanceof ObjectFlow; i = i + 1; } return isObjectFlow; A control token represents the passing of control along a control flow edge. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Return true if the other token is a control token, because control tokens are interchangable. return other instanceof ControlToken; Java // Return a new control token. return new ControlToken(); Java // Return true for a control token. return true; Java // Control tokens do not have values. return null; A control node activation is an activity node activation for a node that is a control node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // By default, offer all tokens on all outgoing edges. if (this.node != null) { Debug.println("[fire] Control node " + this.node.name + "..."); } this.sendOffers(incomingTokens); An activity edge instance is a connection between activity node activations corresponding to an edge between the corresponding nodes of those activations import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The activity edge of which this is an instance. [This is optional to allow for an implicit fork node execution to be connected to its action execution by an edge instance which does not have a corresponding node in the model.] The activity group that contains this activity edge instance. The source of this activity edge instance. The node of the source must be the same as the source of the edge of this edge instance. The target of this activity edge instance. The node of the target must be the same as the target of the edge of this edge instance. Java // Send an offer from the source to the target. // Keep the offered tokens until taken by the target. // (Note that any one edge should only be handling either all object tokens or all control tokens.) Offer offer = new Offer(); for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); // Debug.println("[sendOffer] token value = " + token.getValue()); offer.offeredTokens.addValue(token); } this.offers.addValue(offer); this.target.receiveOffer(); Java // Return the number of values being offered in object tokens. int count = 0; OfferList offers = this.offers; for (int i = 0; i < offers.size(); i++) { count = count + offers.getValue(i).countOfferedValues(); } return count; Java // Take all the offered tokens and return them. TokenList tokens = new TokenList(); while (this.offers.size() > 0) { TokenList offeredTokens = this.offers.getValue(0).getOfferedTokens(); for (int i = 0; i < offeredTokens.size(); i++) { tokens.addValue(offeredTokens.getValue(i)); } this.offers.removeValue(0); } return tokens; Java // Take all the offered tokens, up to the given maximum count of non-null object tokens, and return them. TokenList tokens = new TokenList(); int remainingCount = maxCount; while (this.offers.size() > 0 & remainingCount > 0) { Offer offer = this.offers.getValue(0); TokenList offeredTokens = offer.getOfferedTokens(); int count = offer.countOfferedValues(); if (count <= remainingCount) { for (int i = 0; i < offeredTokens.size(); i++) { tokens.addValue(offeredTokens.getValue(i)); } remainingCount = remainingCount - count; this.offers.removeValue(0); } else { for (int i = 0; i < remainingCount; i++) { Token token = offeredTokens.getValue(i); if (token.getValue() != null) { tokens.addValue(token); } } offer.removeOfferedValues(remainingCount); remainingCount = 0; } } return tokens; Java // Get the offered tokens (after which the tokens will still be offered). TokenList tokens = new TokenList(); OfferList offers = this.offers; for (int i = 0; i < offers.size(); i++) { TokenList offeredTokens = offers.getValue(i).getOfferedTokens(); for (int j = 0; j < offeredTokens.size(); j++) { tokens.addValue(offeredTokens.getValue(j)); } } return tokens; Java // Return true if there are any pending offers. boolean hasTokens = false; int i = 1; while (!hasTokens & i <= this.offers.size()) { hasTokens = this.offers.getValue(i-1).hasTokens(); i = i + 1; } return hasTokens; An activity execution is used to execute a specific activity. The type of the activity execution must be an activity. When executed, the activity execution creates activity edge instances for all activity edges, activity node activations for all activity nodes and makes offers to all nodes with no incoming edges. Execution terminates when either all node activations are complete, or an activity final node is executed. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The group of activations of the activity nodes of the activity. Java // Execute the activity for this execution by creating an activity node activation group and activating all the activity nodes in the activity. // When this is complete, copy the values on the tokens offered by output parameter nodes to the corresponding output parameters. Activity activity = (Activity)(this.getTypes().getValue(0)); Debug.println("[execute] Activity " + activity.name + "..."); // Debug.println("[execute] context = " + this.context.objectId()); Debug.println("[event] Execute activity=" + activity.name); this.activationGroup = new ActivityNodeActivationGroup(); this.activationGroup.activityExecution = this; this.activationGroup.activate(activity.node, activity.edge); // Debug.println("[execute] Getting output parameter node activations..."); ActivityParameterNodeActivationList outputActivations = this.activationGroup.getOutputParameterNodeActivations(); // Debug.println("[execute] There are " + outputActivations.size() + " output parameter node activations."); for (int i = 0; i < outputActivations.size(); i++) { ActivityParameterNodeActivation outputActivation = outputActivations.getValue(i); ParameterValue parameterValue = new ParameterValue(); parameterValue.parameter = ((ActivityParameterNode)(outputActivation.node)).parameter; TokenList tokens = outputActivation.getTokens(); for (int j = 0; j < tokens.size(); j++) { Token token = tokens.getValue(j); Value value = ((ObjectToken)token).value; if (value != null) { parameterValue.values.addValue(value); Debug.println("[event] Output activity="+ activity.name + " parameter=" + parameterValue.parameter.name + " value=" + value); } } this.setParameterValue(parameterValue); } Debug.println("[execute] Activity " + activity.name + " completed."); Java // Create a new activity execution that is a copy of this execution. // [Note: This currently just returns a non-executing execution for the same activity as this execution.] return super.copy(); Java // Create a new activity execution with empty properties. return new ActivityExecution(); Java // Terminate all node activations (which will ultimately result in the activity execution completing). this.activationGroup.terminateAll(); An activity final node activation is a control node activation for a node that is an activity final node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Activities.ExtraStructuredActivities.*; import fUML.Semantics.Loci.*; Java // Terminate the activity execution or structured node activation // containing this activation. Debug.println("[fire] Activity final node " + this.node.name + "..."); if (incomingTokens.size() > 0 | this.incomingEdges.size() == 0) { if (this.group.activityExecution != null) { this.group.activityExecution.terminate(); } else if (this.group.containingNodeActivation != null) { this.group.containingNodeActivation.terminateAll(); } else if (this.group instanceof ExpansionActivationGroup){ ((ExpansionActivationGroup)this.group).regionActivation.terminate(); } } An activity node activation is used to define the behavior of an activity node in the context of a containing activity or structured activity node. import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The group that contains this activity node activation. The activity node being activated by this activity node activation. The node must be owned by the activity (type) of the activity execution of this node activation. [This is optional, to allow for fork node edge queues and implicit fork and join node activations for actions to not have nodes in the model.] The set of activity edge instances for the incoming edges of the node. The set of activity edge instances for the outgoing edges of the node. If true, this node activation is enabled for execution once all its other prerequesites are satisfied. Java // Run the activation of this node. if (this.node != null) { Debug.println("[run] node = " + this.node.name); } else { Debug.println("[run] Anonymous activation of type " + this.getClass().getName()); } this.running = true; Java // Receive an offer from an incoming edge. // Check if all prerequisites have been satisfied. If so, fire. Debug.println("[receiveOffer] " + (this.node == null? "...": "node = " + this.node.name)); _beginIsolation(); boolean ready = this.isReady(); TokenList tokens = new TokenList(); if (ready) { Debug.println("[receiveOffer] Firing."); tokens = this.takeOfferedTokens(); } _endIsolation(); if (ready) { this.fire(tokens); } Java // Get tokens from all incoming edges. TokenList allTokens = new TokenList(); ActivityEdgeInstanceList incomingEdges = this.incomingEdges; for (int i = 0; i < incomingEdges.size(); i++) { ActivityEdgeInstance incomingEdge = incomingEdges.getValue(i); TokenList tokens = incomingEdge.takeOfferedTokens(); for (int j = 0; j < tokens.size(); j ++) { Token token = tokens.getValue(j); allTokens.addValue(token); } } return allTokens; Java // Send offers for the given set of tokens over all outgoing edges (if there are any tokens actually being offered). if (tokens.size()>0) { // *** Send all outgoing offers concurrently. *** ActivityEdgeInstanceList outgoingEdges = this.outgoingEdges; for (Iterator i = outgoingEdges.iterator(); i.hasNext();) { ActivityEdgeInstance outgoingEdge = (ActivityEdgeInstance)i.next(); // Debug.println("[sendOffers] Sending offer to " + outgoingEdge.target.node.name + "."); outgoingEdge.sendOffer(tokens); } } Java // Terminate the activation of this node. if (this.running) { if (this.node != null) { Debug.println("[terminate] node = " + this.node.name); } else { Debug.println("[terminate] Anonymous activation of type " + this.getClass().getName()); } } this.running = false; Java // Check if all the prerequisites for this node have been satisfied. // By default, check that this node is running. return this.isRunning(); Java // Test whether this node activation is running. return this.running; Java // Add an activity edge instance as an outgoing edge of this activity node activation. edge.source = this; this.outgoingEdges.addValue(edge); Java // Add an activity edge instance as an incoming edge of this activity node activation. edge.target = this; this.incomingEdges.addValue(edge); Java // Create node activations for any subnodes of the node for this activation. // For most kinds of nodes, this does nothing. return; Java // Create edge instances for any edge instances owned by the node for this activation. // For most kinds of nodes, this does nothing. return; Java // Check if this node activation is the effective source for the given edge instance. return edgeInstance.source == this; Java // Return the activity execution that contains this activity node activation, directly or indirectly. return this.group.getActivityExecution(); Java // Get the context object for the containing activity execution. return this.getActivityExecution().context; Java // Get the locus of the containing activity execution. return this.getActivityExecution().locus; Java // Get the activity node activation corresponding to the given activity node, in the context of this activity node activation. // By default, return this activity node activation, if it is for the given node, otherwise return nothing. ActivityNodeActivation activation = null; if (node == this.node) { activation = this; } return activation; Java // Transfer the given token to be held by this node. if (this.node == null) { Debug.println("[addToken] ..."); } else { Debug.println("[addToken] node = " + this.node.name); } Token transferredToken = token.transfer(this); // Debug.println("[addToken] Adding token with value = " + transferredToken.getValue()); this.heldTokens.addValue(transferredToken); Java // Remove the given token, if it is held by this node activation. // Return the position (counting from 1) of the removed token (0 if there is none removed). boolean notFound = true; int i = 1; while (notFound & i <= this.heldTokens.size()) { if (this.heldTokens.getValue(i-1) == token) { if (this.node == null) { Debug.println("[removeToken] ..."); } else { Debug.println("[removeToken] node = " + this.node.name); } this.heldTokens.remove(i-1); notFound = false; } i = i + 1; } if (notFound) { i = 0; } else { i = i - 1; } return i ; Java // Transfer the given tokens to be the held tokens for this node. // if (this.node == null) { // Debug.println("[addTokens] ..."); // } else { // Debug.println("[addTokens] node = " + this.node.name); // } for (int i = 0; i < tokens.size(); i++) { Token token = tokens.getValue(i); this.addToken(token); } Java // Take the tokens held by this node activation. TokenList tokens = this.getTokens(); this.clearTokens(); return tokens; Java // Remove all held tokens. while (this.heldTokens.size() > 0) { this.heldTokens.getValue(0).withdraw(); } Java // Get the tokens held by this node activation. // Debug.println("[getTokens] node = " + this.node.name); TokenList tokens = new TokenList(); TokenList heldTokens = this.heldTokens; for (int i = 0; i < heldTokens.size(); i++) { Token heldToken = heldTokens.getValue(i); // Debug.println("[getTokens] token value = " + heldTokens.getValue()); tokens.addValue(heldToken); } return tokens; Java // Suspend this activation within the activation group that contains it. this.group.suspend(this); Java // Resume this activation within the activation group that contains it. this.group.resume(this); Carry out the main behavior of this activity node. An activity node group is a group of nodes that are activated together, either directly in the context of an activity execution, or in the context of import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Activities.CompleteStructuredActivities.*; import fUML.Semantics.Loci.*; The set of activity edge instances for this group. The set of activity node executions for this group. The activity execution to which this group belongs. (This will be empty if the group is for a structured activity node activation.) The structured activity node activation to which this group belongs. (This will be empty if the group is for an activity execution.) Activity node activations in this activation group that are suspended waiting for an event occurrence. If an activation group has a containing node activation and any suspended activations, then the containing node activation will also be suspended. Java // Run the given node activations and then (concurrently) send an offer to all activations for nodes with no incoming edges within the given set. for (int i = 0; i < activations.size(); i++) { ActivityNodeActivation activation = activations.getValue(i); activation.run(); } Debug.println("[run] Checking for enabled nodes..."); ActivityNodeActivationList enabledActivations = new ActivityNodeActivationList(); for (int i = 0; i < activations.size(); i++) { ActivityNodeActivation activation = activations.getValue(i); Debug.println("[run] Checking node " + activation.node.name + "..."); if (activation instanceof ActionActivation | activation instanceof ControlNodeActivation | activation instanceof ActivityParameterNodeActivation) { boolean isEnabled = this.checkIncomingEdges(activation.incomingEdges, activations); // For an action activation, also consider incoming edges to input pins if (isEnabled & activation instanceof ActionActivation) { InputPinList inputPins = ((Action)activation.node).input; int j = 1; while (j <= inputPins.size() & isEnabled) { InputPin inputPin = inputPins.getValue(j-1); ActivityEdgeInstanceList inputEdges = ((ActionActivation)activation).getPinActivation(inputPin).incomingEdges; isEnabled = this.checkIncomingEdges(inputEdges, activations); j = j + 1; } } if (isEnabled) { Debug.println("[run] Node " + activation.node.name + " is enabled."); enabledActivations.addValue(activation); } } } // Debug.println("[run] " + enabledActivations.size() + " node(s) are enabled."); // *** Send offers to all enabled nodes concurrently. *** for (Iterator i = enabledActivations.iterator(); i.hasNext();) { ActivityNodeActivation activation = (ActivityNodeActivation)i.next(); Debug.println("[run] Sending offer to node " + activation.node.name + "."); activation.receiveOffer(); } Java // Check if any incoming edges have a source in a given set of activations. int j = 1; boolean notFound = true; while (j <= incomingEdges.size() & notFound) { int k = 1; while (k <= activations.size() & notFound) { if (activations.getValue(k-1).isSourceFor(incomingEdges.getValue(j-1))) { notFound = false; } k = k + 1; } j = j + 1; } return notFound; Java // Run the node activations associated with the given nodes in this activation group. ActivityNodeActivationList nodeActivations = new ActivityNodeActivationList(); for (int i = 0; i < nodes.size(); i++) { ActivityNode node = nodes.getValue(i); ActivityNodeActivation nodeActivation = this.getNodeActivation(node); if (nodeActivation != null) { nodeActivations.addValue(nodeActivation); } } this.run(nodeActivations); Java // Activate and run the given set of nodes with the given set of edges, within this activation group. this.createNodeActivations(nodes); this.createEdgeInstances(edges); this.run(this.nodeActivations); // Debug.println("[activate] Exiting."); Java // Terminate all node activations in the group. Debug.println("[terminateAll] Terminating activation group for " + (this.activityExecution != null? "activity " + this.activityExecution.getTypes().getValue(0).name: this.containingNodeActivation != null? "node " + this.containingNodeActivation.node.name: "expansion region") + "."); ActivityNodeActivationList nodeActivations = this.nodeActivations; for (int i = 0; i < nodeActivations.size(); i++) { ActivityNodeActivation nodeActivation = nodeActivations.getValue(i); nodeActivation.terminate(); } this.suspendedActivations.clear(); Java // Add activity node activations for the given set of nodes to this group and create edge instances between them. for (int i = 0; i < nodes.size(); i++) { ActivityNode node = nodes.getValue(i); Debug.println("[createNodeActivations] Creating a node activation for " + node.name + "..."); this.createNodeActivation(node); } Java // Create an activity node activation for a given activity node in this activity node activation group. ActivityNodeActivation activation = (ActivityNodeActivation)(this.getActivityExecution().locus.factory.instantiateVisitor(node)); activation.node = node; activation.running = false; this.addNodeActivation(activation); activation.createNodeActivations(); return activation; Java // Add the given node activation to this group. activation.group = this; this.nodeActivations.addValue(activation); Java // Return the node activation (if any) in this group, // or any nested group, corresponding to the given activity node. // If this is a group for a structured activity node activation, // also include the pin activations for that node activation. ActivityNodeActivation activation = null; if (this.containingNodeActivation != null && node instanceof Pin) { activation = this.containingNodeActivation.getPinActivation((Pin)node); } if (activation == null) { int i = 1; while (activation == null & i <= this.nodeActivations.size()) { activation = this.nodeActivations.getValue(i-1).getNodeActivation(node); i = i + 1; } } return activation; Java // Create instance edges for the given activity edges, as well as for edge instances within any nodes activated in this group. for (int i = 0; i < edges.size(); i++) { ActivityEdge edge = edges.getValue(i); Debug.println("[createEdgeInstances] Creating an edge instance from " + edge.source.name + " to " + edge.target.name + "."); ActivityEdgeInstance edgeInstance = new ActivityEdgeInstance(); edgeInstance.edge = edge; this.addEdgeInstance(edgeInstance); this.getNodeActivation(edge.source).addOutgoingEdge(edgeInstance); this.getNodeActivation(edge.target).addIncomingEdge(edgeInstance); // Debug.println("[createEdgeInstances] Edge instance created..."); } ActivityNodeActivationList nodeActivations = this.nodeActivations; for (int i = 0; i < nodeActivations.size(); i++) { ActivityNodeActivation nodeActivation = nodeActivations.getValue(i); nodeActivation.createEdgeInstances(); } // Debug.println("[createEdgeInstances] Done creating edge instances."); Java // Add the given edge instance to this group. instance.group = this; this.edgeInstances.addValue(instance); Java // Return the activity execution to which this group belongs, directly or indirectly. ActivityExecution activityExecution = this.activityExecution; if (activityExecution == null) { activityExecution = this.containingNodeActivation.group.getActivityExecution(); } // Debug.println("[getActivityExecution] activityExecution = " + activityExecution); return activityExecution; Java // Return the set of all activations in this group of activity parameter nodes for output (inout, out and return) parameters. ActivityParameterNodeActivationList parameterNodeActivations = new ActivityParameterNodeActivationList(); ActivityNodeActivationList nodeActivations = this.nodeActivations; for (int i = 0; i < nodeActivations.size(); i++) { ActivityNodeActivation activation = nodeActivations.getValue(i); if (activation instanceof ActivityParameterNodeActivation) { if (activation.incomingEdges.size() > 0) { parameterNodeActivations.addValue((ActivityParameterNodeActivation)activation); } } } return parameterNodeActivations; Java // Returns true if this activation group has a node activation // corresponding to the source of the given edge instance. boolean hasSource = false; ActivityNodeActivationList activations = this.nodeActivations; int i = 1; while (!hasSource & i <= activations.size()) { hasSource = activations.getValue(i-1).isSourceFor(edgeInstance); i = i + 1; } return hasSource; Java // Check if this activitation group has any suspended activations and is, // therefore, itself suspended. return this.suspendedActivations.size() > 0; Java // Suspend the given activation in this activation group. If this is // the only suspended activation, and the activation group has a // containing node activation, then suspend that containing activation. Debug.println("[suspend] node=" + (activation.node == null? "null": activation.node.name)); if (!this.isSuspended()) { StructuredActivityNodeActivation containingNodeActivation = this.containingNodeActivation; if (containingNodeActivation != null) { containingNodeActivation.suspend(); } } this.suspendedActivations.addValue(activation); Java // Resume the given activation by removing it from the suspended // activation list for this activation group. If this is the last // suspended activation, and the activation group has a containing // node activation, then resume that containing activation. Debug.println("[resume] node=" + (activation.node == null? "null": activation.node.name)); boolean found = false; int i = 1; while (!found & i <= this.suspendedActivations.size()) { if (this.suspendedActivations.get(i-1) == activation) { this.suspendedActivations.removeValue(i-1); found = true; } i = i + 1; } if (!this.isSuspended()) { StructuredActivityNodeActivation containingNodeActivation = this.containingNodeActivation; if (containingNodeActivation != null) { containingNodeActivation.resume(); } } An activity parameter node activation is an object node activation for a node that is an activity parameter node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // If there are no incoming edges, this is an activation of an input activity parameter node. // Get the values from the input parameter indicated by the activity parameter node and offer those values as object tokens. if (this.node.incoming.size() == 0) { Debug.println("[fire] Input activity parameter node " + this.node.name + "..."); Parameter parameter = ((ActivityParameterNode)(this.node)).parameter; ParameterValue parameterValue = this.getActivityExecution().getParameterValue(parameter); // Debug.println("[fire] parameter = " + parameter.name); if (parameterValue != null) { Debug.println("[fire] Parameter has " + parameterValue.values.size() + " value(s)."); TokenList tokens = new TokenList(); ValueList values = parameterValue.values; for (int i = 0; i < values.size(); i++) { Value value = values.getValue(i); ObjectToken token = new ObjectToken(); token.value = value; this.addToken(token); } this.sendUnofferedTokens(); } } // If there are one or more incoming edges, this is an activation of an output activity parameter node. // Take the tokens offered on incoming edges and add them to the set of tokens being offered. // [Note that an output activity parameter node may fire multiple times, accumulating tokens offered to it.] else { Debug.println("[fire] Output activity parameter node " + this.node.name + "..."); this.addTokens(incomingTokens); } Java // Clear all held tokens only if this is an input parameter node. if (this.node.incoming.size() == 0) { super.clearTokens(); } Java // Consume all incoming tokens. Debug.println("[fire] Flow final node " + this.node.name + "..."); for (int i = 0; i < incomingTokens.size(); i++) { Token token = incomingTokens.getValue(i); token.withdraw(); } An expansion activation group is an activity node activation group used for activating nodes inside an expansion region. It functions just like a normal activation group, except it has output pin activations corresponding to the input pins and the expansion nodes of the expansion region. Instances of edges from nodes inside the expansion region that connect to region input pins, input expansion nodes or output expansion nodes are redirected to connect to the corresponding "region input", "group input" or "group output" pin, respectively. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Activities.ExtraStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Activities.CompleteStructuredActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Output pin activations corresponding, in order, to the input pins of the expansion region of this activation group. Output pin activations corresponding, in order, to the input expansion nodes of the expansion region of this activation group. The expansion region activation this activation group is for. Output pin activations corresponding, in order, to the output expansion nodes of the expansion region of this activation group. The index (starting at 1) of this activation group in the list held by the expansion region activation. Java // If the given node is an input pin of the expansion region, then return the corresponding region-input output-pin activation. // If the given node is an input expansion node of the expansion region, then return the corresponding group-input output-pin activation. // If the given node is an output expansion node of the expansion region, then return the corresponding group-output output-pin activation. // Otherwise return the node activation from the activation group, as usual. ExpansionRegion region = (ExpansionRegion)(this.regionActivation.node); InputPinList inputs = region.input; ActivityNodeActivation activation = null; int i = 1; while (activation == null & i <= region.input.size()) { if (node == region.input.getValue(i-1)) { activation = this.regionInputs.getValue(i-1); } i = i + 1; } int j = 1; while (activation == null & j <= region.inputElement.size()) { if (node == region.inputElement.getValue(j - 1)) { activation = this.groupInputs.getValue(j - 1); } j = j + 1; } int k = 1; while (activation == null & k <= region.outputElement.size()) { if (node == region.outputElement.getValue(k - 1)) { activation = this.groupOutputs.getValue(k - 1); } k = k + 1; } if (activation == null) { activation = super.getNodeActivation(node); } return activation; Java // Get the activity execution that contains the expansion region activation for this activation group. return this.regionActivation.getActivityExecution(); Java // Suspend the given activation in this activation group. If this is // the only suspended activation, then suspend the associated region // activation. if (!this.isSuspended()) { this.regionActivation.suspend(); } super.suspend(activation); Java // Resume the given activation in this activation group. If this is the // last suspended activation, then resume the associated region // activation. super.resume(activation); if (!this.isSuspended()) { this.regionActivation.resume(this); } import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Activities.ExtraStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Activities.CompleteStructuredActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; Java // Take tokens from all incoming edges. Debug.println("[fire] Expansion node " + this.node.name + "..."); this.addTokens(incomingTokens); Java // Forward the offer on to the expansion region. this.getExpansionRegionActivation().receiveOffer(); Java // An expansion node is always fired by its expansion region. return false; Java // Return the expansion region activation corresponding to this expansion node, in the context of the activity node activation group this expansion node activation is in. ExpansionNode node = (ExpansionNode)(this.node); ExpansionRegion region = node.regionAsInput; if (region == null) { region = node.regionAsOutput; } return (ExpansionRegionActivation)(this.group.getNodeActivation(region)); An expansion region activation is an action activation for a node that is an expansion region. [Note that even though an expansion region is a structured activity node, an expansion region activation is not a structured activity activation because of the special nature of expansion region behavior.] import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Activities.ExtraStructuredActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Activities.CompleteStructuredActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Loci.*; The set of expansion activation groups for this expansion region activation. One activation group is created corresponding to each token held by the first input expansion node activation for the expansion region. The tokens taken from each of the input pin activations for this expansion region activation. These are preserved for initializing the region inputs of each of the activation groups. The tokens taken from each of the input expansion node activations for this expansion region activation. These are preserved for initializing the group input of each of the activation groups. Java // Take the tokens from the input pin and input expansion node activations and save them. super.takeOfferedTokens(); ExpansionRegion region = (ExpansionRegion)(this.node); InputPinList inputPins = region.input; ExpansionNodeList inputElements = region.inputElement; this.inputTokens.clear(); this.inputExpansionTokens.clear(); for (int i = 0; i < inputPins.size(); i++) { InputPin inputPin = inputPins.getValue(i); TokenSet tokenSet = new TokenSet(); tokenSet.tokens = this.getPinActivation(inputPin).takeTokens(); this.inputTokens.addValue(tokenSet); } int n = this.numberOfValues(); for (int i = 0; i < inputElements.size(); i++) { ExpansionNode inputElement = inputElements.getValue(i); ExpansionNodeActivation expansionNodeActivation = this.getExpansionNodeActivation(inputElement); expansionNodeActivation.fire(expansionNodeActivation.takeOfferedTokens()); TokenList tokens = expansionNodeActivation.takeTokens(); TokenSet tokenSet = new TokenSet(); int j = 1; while (j <= n) { tokenSet.tokens.add(tokens.getValue(j-1)); j = j + 1; } this.inputExpansionTokens.addValue(tokenSet); } return new TokenList(); Java // If the expansion region has mustIsolate=true, then carry out its behavior with isolation. // Otherwise just activate it normally. if (((StructuredActivityNode)(this.node)).mustIsolate) { _beginIsolation(); this.doStructuredActivity(); _endIsolation(); } else { this.doStructuredActivity(); } Java // Create a number of expansion region activation groups equal to the number of values expanded in the region, // setting the region inputs and group inputs for each group. // Run the body of the region in each group, either iteratively or in parallel. // Add the outputs of each activation group to the corresonding output expansion node activations. ExpansionRegion region = (ExpansionRegion)this.node; InputPinList inputPins = region.input; ExpansionNodeList inputElements = region.inputElement; ExpansionNodeList outputElements = region.outputElement; this.activationGroups.clear(); int n = this.inputExpansionTokens.getValue(0).tokens.size(); int k = 1; while (k <= n) { ExpansionActivationGroup activationGroup = new ExpansionActivationGroup(); activationGroup.regionActivation = this; activationGroup.index = k; int j = 1; while (j <= inputPins.size()) { OutputPinActivation regionInput = new OutputPinActivation(); regionInput.run(); activationGroup.regionInputs.addValue(regionInput); j = j + 1; } j = 1; while (j <= inputElements.size()) { OutputPinActivation groupInput = new OutputPinActivation(); groupInput.run(); activationGroup.groupInputs.addValue(groupInput); j = j + 1; } j = 1; while (j <= outputElements.size()) { OutputPinActivation groupOutput = new OutputPinActivation(); groupOutput.run(); activationGroup.groupOutputs.addValue(new OutputPinActivation()); j = j + 1; } activationGroup.createNodeActivations(region.node); activationGroup.createEdgeInstances(region.edge); this.activationGroups.addValue(activationGroup); k = k + 1; } ExpansionActivationGroupList activationGroups = this.activationGroups; if (region.mode == ExpansionKind.iterative) { Debug.println("[doStructuredActivity] Expansion mode = iterative"); this.next = 1; this.runIterative(); } else if (region.mode == ExpansionKind.parallel) { Debug.println("[doStructuredActivity] Expansion mode = parallel"); this.runParallel(); } this.doOutput(); Java // Terminate the execution of all contained node activations (which completes the performance of the expansion region activation). ExpansionActivationGroupList activationGroups = this.activationGroups; for (int i = 0; i < activationGroups.size(); i++) { ExpansionActivationGroup activationGroup = this.activationGroups.getValue(i); OutputPinActivationList groupOutputs = activationGroup.groupOutputs; _beginIsolation(); for (int j = 0; j < groupOutputs.size(); j++) { OutputPinActivation groupOutput = groupOutputs.getValue(j); groupOutput.fire(groupOutput.takeOfferedTokens()); } activationGroup.terminateAll(); _endIsolation(); } super.terminate(); Java // Fire all output expansion nodes and send offers on all outgoing control flows. ExpansionRegion region = (ExpansionRegion)(this.node); // *** Send offers from all output expansion nodes concurrently. *** ExpansionNodeList outputElements = region.outputElement; for (Iterator i = outputElements.iterator(); i.hasNext();) { ExpansionNode outputElement = (ExpansionNode)i.next(); this.getExpansionNodeActivation(outputElement).sendUnofferedTokens(); } // Send offers on all outgoing control flows. super.sendOffers(); Java // Set up the inputs for the group with the given index, run the group and then fire the group outputs. if (this.isRunning()) { Debug.println("[runGroup] groupInput[0] = " + this.inputExpansionTokens.getValue(0).tokens.getValue(activationGroup.index-1).getValue()); TokenSetList inputTokens = this.inputTokens; for (int j = 0; j < inputTokens.size(); j++) { TokenSet tokenSet = inputTokens.getValue(j); OutputPinActivation regionInput = activationGroup.regionInputs.getValue(j); regionInput.clearTokens(); regionInput.addTokens(tokenSet.tokens); regionInput.sendUnofferedTokens(); } TokenSetList inputExpansionTokens = this.inputExpansionTokens; for (int j = 0; j < inputExpansionTokens.size(); j++) { TokenSet tokenSet = inputExpansionTokens.getValue(j); OutputPinActivation groupInput = activationGroup.groupInputs.getValue(j); groupInput.clearTokens(); if (tokenSet.tokens.size() >= activationGroup.index) { groupInput.addToken(tokenSet.tokens.getValue(activationGroup.index - 1)); } groupInput.sendUnofferedTokens(); } activationGroup.run(activationGroup.nodeActivations); this.terminateGroup(activationGroup); } Java // Return the expansion node activation corresponding to the given expansion node, in the context of the activity node activation group this expansion region activation is in. // [Note: Expansion regions do not own their expansion nodes. Instead, they are own as object nodes by the enclosing activity or group. // Therefore, they will already be activated along with their expansion region.] return (ExpansionNodeActivation)(this.group.getNodeActivation(node)); Java // Return the number of values to be acted on by the expansion region of // this activation, which is the minimum of the number of values offered // to each of the input expansion nodes of the activation. ExpansionRegion region = (ExpansionRegion) (this.node); ExpansionNodeList inputElements = region.inputElement; int n = this.getExpansionNodeActivation(inputElements.getValue(0)) .countOfferedValues(); int i = 2; while (i <= inputElements.size()) { int count = this.getExpansionNodeActivation( inputElements.getValue(i - 1)).countOfferedValues(); if (count < n) { n = count; } i = i + 1; } return n; Java // Run the body of the region iteratively, either until all activation // groups have run or until the region is suspended. ExpansionActivationGroupList activationGroups = this.activationGroups; while (this.next <= activationGroups.size() & !this.isSuspended()) { ExpansionActivationGroup activationGroup = activationGroups .getValue(this.next-1); this.runGroup(activationGroup); this.next = this.next + 1; } Java // Run the body of the region concurrently. ExpansionActivationGroupList activationGroups = this.activationGroups; // *** Activate all groups concurrently. *** for (Iterator i = activationGroups.iterator(); i.hasNext();) { ExpansionActivationGroup activationGroup = (ExpansionActivationGroup) i .next(); this.runGroup(activationGroup); } Java // Place tokens on the output expansion nodes. ExpansionRegion region = (ExpansionRegion) this.node; ExpansionNodeList outputElements = region.outputElement; Debug.println("[doOutput] Expansion region " + region.name + " is " + (this.isSuspended()? "suspended.": "completed.")); if (!this.isSuspended()) { for (int i = 0; i < activationGroups.size(); i++) { ExpansionActivationGroup activationGroup = activationGroups .getValue(i); OutputPinActivationList groupOutputs = activationGroup.groupOutputs; for (int j = 0; j < groupOutputs.size(); j++) { OutputPinActivation groupOutput = groupOutputs.getValue(j); ExpansionNode outputElement = outputElements.getValue(j); this.getExpansionNodeActivation(outputElement).addTokens( groupOutput.takeTokens()); } } } Java // Terminate the given activation group, after preserving any group outputs. if (this.isRunning() & !this.isSuspended()) { OutputPinActivationList groupOutputs = activationGroup.groupOutputs; for (int i = 0; i < groupOutputs.size(); i++) { OutputPinActivation groupOutput = groupOutputs.getValue(i); groupOutput.fire(groupOutput.takeOfferedTokens()); } activationGroup.terminateAll(); } Java // Check if the activation group for this node is suspended. boolean suspended = false; int i = 1; while (i <= this.activationGroups.size() & !suspended) { ActivityNodeActivationGroup group = this.activationGroups.get(i-1); suspended = group.isSuspended(); i = i + 1; } return suspended; Java // Resume an expansion region after the suspension of the given // activation group. If the region is iterative, then continue with the // iteration. If the region is parallel, and there are no more suspended // activation groups, then generate the expansion node output. ExpansionRegion region = (ExpansionRegion) this.node; this.resume(); this.terminateGroup(activationGroup); if (region.mode == ExpansionKind.iterative) { this.runIterative(); } this.doOutput(); A set of tokens taken from an input pin activation or input expansion node activation for an expansion region. The set of tokens in this input set. A structured value is a Value whose type has structural features: a data type (but not a primitive type or enumeration), a class or an association. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Return an instance value that specifies this structured value. // Debug.println("[specify] StructuredValue..."); InstanceValue instanceValue = new InstanceValue(); InstanceSpecification instance = new InstanceSpecification(); instanceValue.type = null; instanceValue.instance = instance; instance.classifier = this.getTypes(); FeatureValueList featureValues = this.getFeatureValues(); // Debug.println("[specify] " + featureValues.size() + " feature(s)."); for (int i = 0; i < featureValues.size(); i++) { FeatureValue featureValue = featureValues.getValue(i); Slot slot = new Slot(); slot.definingFeature = featureValue.feature; // Debug.println("[specify] feature = " + featureValue.feature.name + ", " + featureValue.values.size() + " value(s)."); ValueList values = featureValue.values; for (int j = 0; j < values.size(); j++) { Value value = values.getValue(j); // Debug.println("[specify] value = " + value); slot.value.addValue(value.specify()); } instance.slot.addValue(slot); } return instanceValue; Java // Create empty feature values for all structural features, direct and inherited, of the types of this structured value. ClassifierList types = this.getTypes(); for (int i = 0; i < types.size(); i++) { Classifier type = types.getValue(i); NamedElementList members = type.member; for (int j = 0; j < members.size(); j++) { NamedElement member = members.getValue(j); if (member instanceof StructuralFeature) { this.setFeatureValue((StructuralFeature)member, new ValueList(), 0); } } } Get the feature value associated with the given feature. The given feature must be a structural feature of the type of the structured value. Set the value(s) and, optionally, the position index associated with the given feature. The given feature must be a structural feature of the type of the structured value. Return the feature values associated with this structural value. An unlimited natural value is a primitive value whose type is UnlimitedNatural. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The actual unlimited natural value. Java // Return a literal unlimited natural with the value of this unlimited natural value. LiteralUnlimitedNatural literal = new LiteralUnlimitedNatural(); literal.type = this.type; literal.value = this.value; return literal; Java // Test if this unlimited natural value is equal to the otherValue. // To be equal, the otherValue must have the same value as this unlimited natural value. boolean isEqual = false; if (otherValue instanceof UnlimitedNaturalValue) { isEqual = ((UnlimitedNaturalValue)otherValue).value == this.value; } return isEqual; Java // Create a new unlimited natural value with the same value as this value. UnlimitedNaturalValue newValue = (UnlimitedNaturalValue)(super.copy()); newValue.value = this.value; return newValue; Java // Create a new unlimited natural value with no value. return new UnlimitedNaturalValue(); Java String stringValue = "*"; if (this.value.naturalValue >= 0) { IntegerValue integerValue = new IntegerValue(); integerValue.value = this.value.naturalValue; stringValue = integerValue.toString(); } return stringValue; A value is an instance of one or more classifiers, which are its types. A value is always representable using a value specification. [Note: Value specializes SemanticVisitor to allow the Execution subclass to be a semantic visitor, without requiring multiple generalization of Execution.] import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Test if this value is equal to otherValue. To be equal, this value must have the same type as otherValue. // This operation must be overridden in Value subclasses to check for equality of properties defined in those subclasses. ClassifierList myTypes = this.getTypes(); ClassifierList otherTypes = otherValue.getTypes(); boolean isEqual = true; // Debug.println("[equals] Value..."); // Debug.println("[equals] this has " + myTypes.size() + "types, other has " + otherTypes.size() + "."); if (myTypes.size() != otherTypes.size()) { isEqual = false; } else { // Debug.println("[equals] " + myTypes.size() + " type(s)."); int i = 1; while (isEqual & i <= myTypes.size()) { // Debug.println("[equals] this type = " + myTypes.getValue(i-1).name); boolean matched = false; int j = 1; while (!matched & j <= otherTypes.size()) { // Debug.println("[equals] other type = " + otherTypes.getValue(j-1).name); matched = (otherTypes.getValue(j-1) == myTypes.getValue(i-1)); j = j + 1; } isEqual = matched; i = i + 1; } } return isEqual; Java // Create a new value that is equal to this value. // By default, this operation simply creates a new value with empty properties. // It must be overridden in each Value subclass to do the superclass copy and then appropriately set properties defined in the subclass. return this.new_(); Java // Check if this object has the given classifier as a type. ClassifierList types = this.getTypes(); boolean found = false; int i = 1; while (!found & i <= types.size()) { found = (types.getValue(i-1) == type); i = i + 1; } return found; Java // Return an identifier for this object. // [Non-normative.] return super.toString(); Return a value specification whose evaluation gives a value equal to this value. Create a new value of the same Value subclass as this value, with all properties empty (even if this violates multiplicity constraints). This operation must be defined in each concrete Value subclass to create an instance of that subclass. Gets all the classifiers under which this value is currently classifier. Return a string representation of this value. A string value is a primitive value whose type is String. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Return a literal string with the value of this string value. LiteralString literal = new LiteralString(); literal.type = this.type; literal.value = this.value; return literal; Java // Test if this string value is equal to the otherValue. // To be equal, the otherValue must have the same value as this string value. boolean isEqual = false; if (otherValue instanceof StringValue) { isEqual = ((StringValue)otherValue).value.equals(this.value); } return isEqual; Java // Create a new string value with the same value as this string value. StringValue newValue = (StringValue)(super.copy()); newValue.value = this.value; return newValue; Java // Create a new string value with no value. return new StringValue(); Java return value; A reference is an access path to a specific object. There may be multiple references to the same object. As a structured value, the reference acts just the same as its referent in terms of type, features, operations, etc. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Asynchronously start the behavior of the given classifier for the referent object. this.referent.startBehavior(classifier, inputs); Java // Dispatch the given operation to the referent object. return this.referent.dispatch(operation); Java // Send the given signal instance to the referent object. this.referent.send(signalInstance); Java // Destroy the referent. this.referent.destroy(); Java // Test if this reference is equal to the otherValue. // To be equal, the otherValue must also be a reference, with the same referent as this reference. boolean isEqual = false; if (otherValue instanceof Reference) { isEqual = (((Reference)otherValue).referent == this.referent); } return isEqual; Java // Create a new reference with the same referent as this reference. Reference newValue = (Reference)(super.copy()); newValue.referent = this.referent; return newValue; Java // Create a new reference with no referent. return new Reference(); Java // Get the types of the referent object. return this.referent.getTypes(); Java // Get the feature value associated with the given feature in the referent object. return this.referent.getFeatureValue(feature); Java // Set the values associated with the given feature in the referent object. this.referent.setFeatureValue(feature, values, position); Java // Return the feature values of the referent. return this.referent.getFeatureValues(); Java return "Reference to " + this.referent.toString(); A primitive value is a value whose (single) type is a primitive type. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Create a new value that is equal to this primitive value. PrimitiveValue newValue = (PrimitiveValue)(super.copy()); newValue.type = this.type; return newValue; Java // Return the single primitive type of this value. ClassifierList types = new ClassifierList(); types.addValue(this.type); return types; An object is an extensional value that may have multiple types, all of which must be classes. (Note that a destroyed object has no types.) An object has a unique identity. Usually, references to objects are manipulated, rather than the objects themselves, and there may be multiple references to the same object. If an object is active, it has an object activation that handle the execution of its classifier behavior(s). import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Loci.*; The classes under which this object is currently classified. (A destroyed object has no types.) The object activation handling the active behavior of this object. Java // Create an object activation for this object (if one does not already exist) and start its behavior(s). // Debug.println("[startBehavior] On object..."); if (this.objectActivation == null) { this.objectActivation = new ObjectActivation(); this.objectActivation.object = this; } // Debug.println("[startBehavior] objectActivation = " + objectActivation); this.objectActivation.startBehavior(classifier, inputs); Java // Dispatch the given operation to a method execution, using a dispatch strategy. return ((DispatchStrategy)this.locus.factory.getStrategy("dispatch")).dispatch(this, operation); Java // If the object is active, add the given signal instance to the event pool and signal that a new signal instance has arrived. if (this.objectActivation != null) { this.objectActivation.send(signalInstance); } Java // Stop the object activation (if any), clear all types and destroy the object as an extensional value. Debug.println("[destroy] object = " + this.objectId()); if (this.objectActivation != null) { this.objectActivation.stop(); this.objectActivation = null; } this.types.clear(); super.destroy(); Java // Register the given accept event accepter to wait for a dispatched signal event. if (this.objectActivation != null) { this.objectActivation.register(accepter); } Java // Remove the given event accepter for the list of waiting event accepters. if (this.objectActivation != null) { this.objectActivation.unregister(accepter); } Java // Create a new object that is a copy of this object at the same locus as this object. // However, the new object will NOT have any object activation (i.e, its classifier behaviors will not be started). Object_ newObject = (Object_)(super.copy()); Class_List types = this.types; for (int i = 0; i < types.size(); i++) { Class_ type = types.getValue(i); newObject.types.addValue(type); } return newObject; Java // Create a new object with no type, feature values or locus. return new Object_(); Java // Return the types of this object. ClassifierList types = new ClassifierList(); Class_List myTypes = this.types; for (int i = 0; i < myTypes.size(); i++) { Class_ type = myTypes.getValue(i); types.addValue(type); } return types; A boolean evaluation is an evaluation whose specification is a literal boolean. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a literal boolean, producing a boolean value. LiteralBoolean literal = (LiteralBoolean)specification; BooleanValue booleanValue = new BooleanValue(); booleanValue.type = this.getType("Boolean"); booleanValue.value = literal.value; return booleanValue; A literal evaluation is an evaluation whose specification is a Literal Specification. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Get the type of the specification. If that is null, then use the built-in type of the given name. PrimitiveType type = (PrimitiveType)(this.specification.type); if (type == null) { type = this.locus.factory.getBuiltInType(builtInTypeName); } return type; A literal integer evaluation is an evaluation whose specification is a literal integer. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a literal integer, producing an integer value. LiteralInteger literal = (LiteralInteger)specification; IntegerValue integerValue = new IntegerValue(); integerValue.type = this.getType("Integer"); integerValue.value = literal.value; return integerValue; A literal null evaluation is an evaluation whose specification is a literal null. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a literal null, returning nothing (since a null represents an "absence of any value"). return null; A literal string evaluation is an evaluation whose specification is a literal string. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a literal string, producing a string value. LiteralString literal = (LiteralString)specification; StringValue stringValue = new StringValue(); stringValue.type = this.getType("String"); stringValue.value = literal.value; return stringValue; A literal unlimited natural evaluation is an evaluation whose specification is a literal unlimited natural. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a literal unlimited natural producing an unlimited natural value. LiteralUnlimitedNatural literal = (LiteralUnlimitedNatural)specification; UnlimitedNaturalValue unlimitedNaturalValue = new UnlimitedNaturalValue(); unlimitedNaturalValue.type = this.getType("UnlimitedNatural"); unlimitedNaturalValue.value = literal.value; return unlimitedNaturalValue; A link is an extensional value whose (single) type is an association. (However, if the link has been destroyed, then it has no type.) A link must at have most one feature value for each structural feature owned by its type. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The type of this link. Java // Remove the type of this link and destroy it. // Shift the positions of the feature values of any remaining links in // the extent of the same association, for ends that are ordered. Debug.println("[destroy] link = " + this.objectId()); PropertyList ends = this.type.memberEnd; ExtensionalValueList extent = this.locus.getExtent(this.type); for (int i = 0; i < extent.size(); i++) { ExtensionalValue otherLink = extent.getValue(i); for (int j=0; j < ends.size(); j++) { Property end = ends.getValue(j); if (end.multiplicityElement.isOrdered) { FeatureValue featureValue = otherLink.getFeatureValue(end); if (this.getFeatureValue(end).position < featureValue.position) { featureValue.position = featureValue.position - 1; } } } } this.type = null; super.destroy(); Java // Create a new link with the same type, locus and feature values as this link. Link newValue = (Link)(super.copy()); newValue.type = this.type; return newValue; Java // Create a new link with no type or properies. return new Link(); Java // Return the single type of this link (if any). ClassifierList types = null; if (this.type == null) { types = new ClassifierList(); } else { types = new ClassifierList(); types.addValue(this.type); } return types; Java // Test whether the given link matches the values of this link on all // ends other than the given end. PropertyList ends = this.type.memberEnd; boolean matches = true; int i = 1; while (matches & i <= ends.size()) { Property otherEnd = ends.getValue(i - 1); if (otherEnd != end & !this.getFeatureValue(otherEnd).values.getValue(0).equals( link.getFeatureValue(otherEnd).values.getValue(0))) { matches = false; } i = i + 1; } return matches; Java // Return all feature values for the given end of links in the given // extent whose other ends match this link. FeatureValueList featureValues = new FeatureValueList(); for (int i = 0; i < extent.size(); i++) { ExtensionalValue link = extent.getValue(i); if (link != this) { if (isMatchingLink(link, end)) { featureValues.addValue(link.getFeatureValue(end)); } } } return featureValues; Java // Add this link to the extent of its association at the given locus. // Shift the positions of ends of other links, as appropriate, for ends // that are ordered. Debug.println("[addTo] link = " + this.objectId()); PropertyList ends = this.type.memberEnd; ExtensionalValueList extent = locus.getExtent(this.type); for (int i = 0; i < ends.size(); i++) { Property end = ends.getValue(i); if (end.multiplicityElement.isOrdered) { FeatureValue featureValue = this.getFeatureValue(end); FeatureValueList otherFeatureValues = this.getOtherFeatureValues(extent, end); int n = otherFeatureValues.size(); if (featureValue.position < 0 | featureValue.position > n) { featureValue.position = n + 1; } else { if (featureValue.position == 0) { featureValue.position = 1; } for (int j = 0; j < otherFeatureValues.size(); j++) { FeatureValue otherFeatureValue = otherFeatureValues.getValue(j); if (featureValue.position <= otherFeatureValue.position) { otherFeatureValue.position = otherFeatureValue.position + 1; } } } } } locus.add(this); An instance value evaluation is an evaluation whose specification is an instance value. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; Java // If the instance specification is for an enumeration, then return the identified enumeration literal. // If the instance specification is for a data type (but not a primitive value or an enumeration), then create a data value of the given data type. // If the instance specification is for an object, then create an object at the current locus with the specified types. // Set each feature of the created value to the result of evaluating the value specifications for the specified slot for the feature. // Debug.println("[evaluate] InstanceValueEvaluation..."); InstanceSpecification instance = ((InstanceValue)this.specification).instance; ClassifierList types = instance.classifier; Classifier myType = types.getValue(0); Debug.println("[evaluate] type = " + myType.name); Value value; if (instance instanceof EnumerationLiteral) { // Debug.println("[evaluate] Type is an enumeration."); EnumerationValue enumerationValue = new EnumerationValue(); enumerationValue.type = (Enumeration)myType; enumerationValue.literal = (EnumerationLiteral)instance; value = enumerationValue; } else { StructuredValue structuredValue = null; if (myType instanceof DataType) { // Debug.println("[evaluate] Type is a data type."); DataValue dataValue = new DataValue(); dataValue.type = (DataType)myType; structuredValue = dataValue; } else { Object_ object = null; if (myType instanceof Behavior) { // Debug.println("[evaluate] Type is a behavior."); object = this.locus.factory.createExecution((Behavior)myType, null); } else { // Debug.println("[evaluate] Type is a class."); object = new Object_(); for (int i = 0; i < types.size(); i++) { Classifier type = types.getValue(i); object.types.addValue((Class_)type); } } this.locus.add(object); Reference reference = new Reference(); reference.referent = object; structuredValue = reference; } structuredValue.createFeatureValues(); // Debug.println("[evaluate] " + instance.slot.size() + " slot(s)."); SlotList instanceSlots = instance.slot; for (int i = 0; i < instanceSlots.size(); i++) { Slot slot = instanceSlots.getValue(i); ValueList values = new ValueList(); // Debug.println("[evaluate] feature = " + slot.definingFeature.name + ", " + slot.value.size() + " value(s)."); ValueSpecificationList slotValues = slot.value; for (int j = 0; j < slotValues.size(); j++) { ValueSpecification slotValue = slotValues.getValue(j); // Debug.println("[evaluate] Value = " + slotValue.getClass().getName()); values.addValue(this.locus.executor.evaluate(slotValue)); } structuredValue.setFeatureValue(slot.definingFeature, values, 0); } value = structuredValue; } return value; An integer value is a primitive value whose type is Integer. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The actual Integer value. Java // Return a literal integer with the value of this integer value. LiteralInteger literal = new LiteralInteger(); literal.type = this.type; literal.value = this.value; return literal; Java // Test if this integer value is equal to the otherValue. // To be equal, the otherValue must have the same value as this integer value. boolean isEqual = false; if (otherValue instanceof IntegerValue) { isEqual = ((IntegerValue)otherValue).value == this.value; } return isEqual; Java // Create a new integer value with the same value as this integer value. IntegerValue newValue = (IntegerValue)(super.copy()); newValue.value = this.value; return newValue; Java // Create a new integer value with no value. return new IntegerValue(); Java String stringValue = ""; if (this.value == 0) { stringValue = "0"; } else { int positiveValue = this.value; if (positiveValue < 0) { positiveValue = -positiveValue; } do { int digit = positiveValue % 10; if (digit == 0) { stringValue = "0" + stringValue; } else if (digit == 1) { stringValue = "1" + stringValue; } else if (digit == 2) { stringValue = "2" + stringValue; } else if (digit == 3) { stringValue = "3" + stringValue; } else if (digit == 4) { stringValue = "4" + stringValue; } else if (digit == 5) { stringValue = "5" + stringValue; } else if (digit == 6) { stringValue = "6" + stringValue; } else if (digit == 7) { stringValue = "7" + stringValue; } else if (digit == 8) { stringValue = "8" + stringValue; } else if (digit == 9) { stringValue = "9" + stringValue; } positiveValue = positiveValue / 10; } while (positiveValue > 0); if (this.value < 0) { stringValue = "-" + stringValue; } } return stringValue; A feature value gives the value(s) that a single structural feature has in a specific structured value. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The structural feature being given value(s). The values of for the feature. Zero or more values are possible, as constrained by the multiplicity of the feature. The position of this feature value in a set of ordered values for a feature of an association. [This is only relevant if the feature value is for a link and the feature is ordered.] Java // Determine if this feature value has an equal set of values as another feature value. // If the feature is ordered, then the values also have to be in the same order. boolean equal = true; if (this.values.size() != other.values.size()) { equal = false; } else { // Debug.println("[hasEqualValues] feature = " + this.feature.name + ", " + this.values.size() + " value(s)."); if (this.feature.multiplicityElement.isOrdered) { int i = 1; while (equal & i <= this.values.size()) { equal = this.values.getValue(i-1).equals(other.values.getValue(i-1)); i = i + 1; } } else { // Note: otherFeatureValues is used here solely as a holder for a copy of the list of other values, // since the Java to UML mapping conventions do not allow "remove" on a local list variable. FeatureValue otherFeatureValues = new FeatureValue(); ValueList values = other.values; for (int i=0; i < values.size(); i++) { Value value = values.getValue(i); otherFeatureValues.values.addValue(value); } int i = 1; while (equal & i <= this.values.size()) { // Debug.println("[hasEqualValues] This value [" + (i-1) + "] = " + this.values.getValue(i-1)); boolean matched = false; int j = 1; while (!matched & j <= otherFeatureValues.values.size()) { if (this.values.getValue(i-1).equals(otherFeatureValues.values.getValue(j-1))) { // Debug.println("[hasEqualValues] Other value [" + (j-1) + "] = " + otherFeatureValues.values.getValue(j-1)); matched = true; otherFeatureValues.values.remove(j-1); } j = j + 1; } equal = matched; i = i + 1; } } } return equal; Java // Create a copy of this feature value. FeatureValue newValue = new FeatureValue(); newValue.feature = this.feature; newValue.position = this.position; ValueList values = this.values; for (int i = 0; i < values.size(); i ++) { Value value = values.getValue(i); newValue.values.addValue(value.copy()); } return newValue; An extensional value is a data value that is part of the extent of some classifier at a specific locus. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The locus of the extent of which this value is a member. (If the value has been destroyed, it has no locus.) Java // Remove this value from its locus (if it has not already been destroyed). if (this.locus != null) { this.locus.remove(this); } Java // Create a new extensional value with the same feature values at the same locus as this one. ExtensionalValue newValue = (ExtensionalValue)(super.copy()); if (this.locus != null) { this.locus.add(newValue); } return newValue; An evaluation is used to evaluate a value specification to produce a value. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The value specification to be evaluated. The locus at which this evaluation is taking place. Evaluate the specification, returning the resulting value. An enumeration value is a value whose (single) type is an enumeration. It's literal must be an owned literal of it's type. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The literal value of this enumeration value. Java // Return an instance value with literal as the instance. InstanceValue instanceValue = new InstanceValue(); InstanceSpecification instance = new InstanceSpecification(); instanceValue.type = this.type; instanceValue.instance = this.literal; return instanceValue; Java // Test if this enumeration value is equal to the otherValue. // To be equal, the otherValue must also be an enumeration value with the same literal as this enumeration value. boolean isEqual = false; if (otherValue instanceof EnumerationValue) { isEqual = ((EnumerationValue)otherValue).literal == this.literal; } return isEqual; Java // Create a new enumeration value with the same literal as this enumeration value. EnumerationValue newValue = (EnumerationValue)(super.copy()); newValue.type = this.type; newValue.literal = this.literal; return newValue; Java // Create a new enumeration value with no literal. return new EnumerationValue(); Java // Return the single type of this enumeration value. ClassifierList types = new ClassifierList(); types.addValue(this.type); return types; Java return literal.name; A data value is a compund value whose (single) type is a data type other than a primitive type or an enumeration. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The type of this data value. This must not be a primitive or an enumeration. Java // Return the single type of this data value. ClassifierList types = new ClassifierList(); types.addValue(this.type); return types; Java // Create a new data value with the same type and feature values as this data value. DataValue newValue = (DataValue)(super.copy()); newValue.type = this.type; return newValue; Java // Create a new data value with no type or feature values. return new DataValue(); A compound value is a structured value with by-value semantics. Values are associated with each structural feature specified by the type(s) of the compound value. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Test if this data value is equal to the otherValue. // To be equal, the otherValue must also be a compund value with the same types and equal values for each feature. // Debug.println("[equals] othervalue instanceof CompoundValue = " + (otherValue instanceof CompoundValue)); // Debug.println("[equals] super.equals(otherValue) = " + super.equals(otherValue)); boolean isEqual = otherValue instanceof CompoundValue; if (isEqual) { CompoundValue otherCompoundValue = (CompoundValue)otherValue; // Debug.println("[equals] " + this.featureValues.size() + " feature(s)."); isEqual = super.equals(otherValue) & otherCompoundValue.featureValues.size() == this.featureValues.size(); int i = 1; while (isEqual & i <= this.featureValues.size()) { FeatureValue thisFeatureValue = this.featureValues.getValue(i-1); boolean matched = false; int j = 1; while (!matched & j <= otherCompoundValue.featureValues.size()) { FeatureValue otherFeatureValue = otherCompoundValue.featureValues.getValue(j-1); if (thisFeatureValue.feature == otherFeatureValue.feature) { matched = thisFeatureValue.hasEqualValues(otherFeatureValue); } j = j + 1; } isEqual = matched; i = i + 1; } } return isEqual; Java // Create a new data value with the same featureValues as this data value. CompoundValue newValue = (CompoundValue)(super.copy()); FeatureValueList featureValues = this.featureValues; for (int i = 0; i < featureValues.size(); i++) { FeatureValue featureValue = featureValues.getValue(i); newValue.featureValues.addValue(featureValue.copy()); } return newValue; Java // Get the value(s) of the member of featureValues for the given feature. FeatureValue featureValue = null; int i = 1; while (featureValue == null & i <= this.featureValues.size()) { if (this.featureValues.getValue(i-1).feature == feature) { featureValue = this.featureValues.getValue(i-1); } i = i + 1; } return featureValue; Java // Set the value(s) of the member of featureValues for the given feature. FeatureValue featureValue = this.getFeatureValue(feature); if (featureValue == null) { featureValue = new FeatureValue(); this.featureValues.addValue(featureValue); } featureValue.feature = feature; featureValue.values = values; featureValue.position = position; Java // Return the feature values for this compound value. return this.featureValues; Java // Remove all feature values for features whose type is the given classifier. int i = 1; while (i <= this.featureValues.size()) { if (this.featureValues.getValue(i-1).feature.typedElement.type == classifier) { this.featureValues.remove(i-1); } else { i = i + 1; } } Java String buffer = "(" + this.objectId() + ":"; ClassifierList types = this.getTypes(); int i = 1; while (i <= types.size()) { buffer = buffer +" " + types.getValue(i-1).name; i = i + 1; } int k = 1; while (k <= this.featureValues.size()) { FeatureValue featureValue = this.featureValues.getValue(k-1); buffer = buffer + "\n\t\t" + featureValue.feature.name + "[" + featureValue.position + "] ="; int j = 1; while (j <= featureValue.values.size()) { buffer = buffer + " " + featureValue.values.getValue(j-1).toString(); j = j + 1; } k = k + 1; } return buffer + ")"; A boolean value is a primitive value whose type is Boolean. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The actual Boolean value. Java // Return a literal boolean with the value of this boolean value. LiteralBoolean literal = new LiteralBoolean(); literal.type = this.type; literal.value = this.value; return literal; Java // Test if this boolean value is equal to the otherValue. // To be equal, the otherValue must have the same value as this boolean value. boolean isEqual = false; if (otherValue instanceof BooleanValue) { isEqual = ((BooleanValue)otherValue).value == this.value; } return isEqual; Java // Create a new boolean value with the same value as this boolean value. BooleanValue newValue = (BooleanValue)(super.copy()); newValue.value = this.value; return newValue; Java // Return a new boolean value with no value. return new BooleanValue(); Java String stringValue = "false"; if (this.value) { stringValue = "true"; } return stringValue; The set of values that are members of classifier extents at this locus. A dispatch strategy is a semantic strategy for the polymorphic dispatching of an operation to an execution of a method for that operation. Java // Dispatch strategies are always named "dispatch". return "dispatch"; Java // Get the behavior for the given operation as determined by the type(s) of the given object, compile the behavior at the locus of the object, and return the resulting execution object. return object.locus.factory.createExecution(this.getMethod(object,operation), object); // Get the method that corresponds to the given operation for the given object. A redefinition-based dispatch strategy is one that requires: - each non-abstract operation to have exactly one method - an overriding subclass operation to explicitly redefine the overridden superclass operation. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.CommonBehaviors.Communications.*; import fUML.Semantics.Loci.*; Java // Get the method that corresponds to the given operation for the given object. // [If there is more than one type with a method for the operation, then the first one is arbitrarily chosen.] Behavior method = null; int i = 1; while (method == null & i <= object.types.size()) { Class_ type = object.types.getValue(i-1); NamedElementList members = type.member; int j = 1; while (method == null & j <= members.size()) { NamedElement member = members.getValue(j-1); if (member instanceof Operation) { Operation memberOperation = (Operation)member; if (this.operationsMatch(memberOperation, operation)) { method = memberOperation.method.getValue(0); } } j = j + 1; } i = i + 1; } return method; Java // Check if the owned operation is equal to or a redefinition (directly or indirectly) of the base operation. boolean matches = false; if (ownedOperation == baseOperation) { matches = true; } else { int i = 1; while (!matches & i <= ownedOperation.redefinedOperation.size()) { matches = this.operationsMatch(ownedOperation.redefinedOperation.getValue(i-1), baseOperation); i = i + 1; } } return matches; A literal real evaluation is an evaluation whose specification is a literal real. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; Java // Evaluate a real integer, producing a real value. LiteralReal literal = (LiteralReal)specification; RealValue realValue = new RealValue(); realValue.type = this.getType("Real"); realValue.value = literal.value; return realValue; A real value is a primitive value whose type is Real. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Loci.*; The actual Real value. Java // Create a new real value with the same value as this real value. RealValue newValue = (RealValue)(super.copy()); newValue.value = this.value; return newValue; Java // Test if this real value is equal to the otherValue. // To be equal, the otherValue must have the same value as this real value. boolean isEqual = false; if (otherValue instanceof RealValue) { isEqual = ((RealValue)otherValue).value == this.value; } return isEqual; Java return new RealValue(); Java // Return a literal real with the value of this real value. LiteralReal literal = new LiteralReal(); literal.type = this.type; literal.value = this.value; return literal; Java String stringValue = ""; if (this.value == 0) { stringValue = "0"; } else { float positiveValue = this.value; if (positiveValue < 0) { positiveValue = -positiveValue; } int exponent = 0; if (positiveValue < .1) { while (positiveValue < .1) { positiveValue = positiveValue * 10; exponent = exponent - 1; } } else if (positiveValue > 1) { while (positiveValue > 1) { positiveValue = positiveValue / 10; exponent = exponent + 1; } } // This gives 10 significant digits in the mantissa. for (int i=0; i<10; i++) { positiveValue = positiveValue * 10; } IntegerValue integerValue = new IntegerValue(); integerValue.value = (int)positiveValue; stringValue = "0." + integerValue.toString(); integerValue.value = exponent; stringValue = stringValue + "E" + integerValue.toString(); if (this.value < 0) { stringValue = "-" + stringValue; } } return stringValue; A parameter value gives the value(s) for a specific parameter. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.Loci.*; The values of for the parameter. Zero or more values are possible, as constrained by the multiplicity of the parameter. Java // Create a new parameter value for the same parameter as this parameter value, but with copies of the values of this parameter value. ParameterValue newValue = new ParameterValue(); newValue.parameter = this.parameter; ValueList values = this.values; for (int i = 0; i < values.size(); i++) { Value value = values.getValue(i); newValue.values.addValue(value.copy()); } return newValue; An opaque execution is an execution for an opaque behavior. Opaque behaviors are used to define primitive behaviors. The actual definition of the primitive behavior should be given in a concrete subclass of OpaqueBehaviorExecution. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.Loci.*; Java // Execute the body of the opaque behavior. Debug.println("[execute] Opaque behavior " + this.getBehavior().name + "..."); ParameterList parameters = this.getBehavior().ownedParameter; ParameterValueList inputs = new ParameterValueList(); ParameterValueList outputs = new ParameterValueList(); for (int i = 0; i < parameters.size(); i++) { Parameter parameter = parameters.getValue(i); if ((parameter.direction == ParameterDirectionKind.in) | (parameter.direction == ParameterDirectionKind.inout)) { inputs.addValue(this.getParameterValue(parameter)); } if ((parameter.direction == ParameterDirectionKind.inout) | (parameter.direction == ParameterDirectionKind.out) | (parameter.direction == ParameterDirectionKind.return_)) { ParameterValue parameterValue = new ParameterValue(); parameterValue.parameter = parameter; this.setParameterValue(parameterValue); outputs.addValue(parameterValue); } } this.doBody(inputs, outputs); The actual definition of the behavior of an Opaque Behavior should be given in a concrete subclass that defines this operation. The values of the inputParameters are set when the operation is called. The values of the outputParmeters should be set during the execution of the operation. An execution is used to execute a specific behavior. Since a behavior is a kind of class, an execution is an object with the behavior as its type. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.Loci.*; The object that provides the context for this execution. The type of the context of the execution must be the context of the type (behavior) of the execution. The parameterValues for this execution. All parameterValues must have a parameter that is a parameter of the type of this execution. The values of all input (in and in-out) parameters must be set before the execution is executed. Java // Terminate an ongoing execution. By default, do nothing. return; Java // Create a new execution that has the same behavior and parameterValues as this execution. // Debug.println("[Copy] execution = " + this); Execution newValue = (Execution)(super.copy()); newValue.context = this.context; ParameterValueList parameterValues = this.parameterValues; for (int i = 0; i < parameterValues.size(); i++) { ParameterValue parameterValue = parameterValues.getValue(i); newValue.parameterValues.addValue(parameterValue.copy()); } // Debug.println("[Copy] Done."); return newValue; Java // Set the given parameter value for this execution. // If a parameter value already existed for the parameter of the given parameter value, then replace its value. // Debug.println("[setParameterValue] parameter = " + parameterValue.parameter.name + " with " + parameterValue.values.size() + " values"); ParameterValue existingParameterValue = this.getParameterValue(parameterValue.parameter); if (existingParameterValue == null) { this.parameterValues.addValue(parameterValue); } else { existingParameterValue.values = parameterValue.values; } Java // Get the parameter value of this execution corresponding to the given parameter (if any). ParameterValue parameterValue = null; int i = 1; while (parameterValue == null & i <= this.parameterValues.size()) { if (this.parameterValues.getValue(i-1).parameter == parameter) { parameterValue = this.parameterValues.getValue(i-1); } i = i + 1; } return parameterValue; Java // Return the parameter values for output (in-out, out and return) parameters. ParameterValueList outputs = new ParameterValueList(); ParameterValueList parameterValues = this.parameterValues; for (int i = 0; i < parameterValues.size(); i++) { ParameterValue parameterValue = parameterValues.getValue(i); Parameter parameter = parameterValue.parameter; if ((parameter.direction == ParameterDirectionKind.inout) | (parameter.direction == ParameterDirectionKind.out) | (parameter.direction == ParameterDirectionKind.return_)) { outputs.addValue(parameterValue); } } return outputs; Java // Get the behavior that is the type of this execution. return (Behavior)(this.getTypes().getValue(0)); Execute the behavior given by the type of this execution. The parameterValues for any input (in or in-out) parameters of the behavior should be set before the execution. The parameteValues for any output (in-out, out or return) parameters of the behavior will be set by the execution. Create a new execution with no behavior or parameterValues. An event accepter handles signal reception events. This is an abstract class intended to provide a common interface for different kinds of event accepters. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; Accept a signal occurance for the given signal instance. Determine if the given signal instance matches a trigger of this event accepter. A classifier behavior execution executes the classifier behavior from a specific active class. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; The execution of the associated classifier behavior for a certain object. The classifier whose behavior is being executed. (This must be an active class.) The object activation that owns this classifier behavior execution. Java Java // Set the classifier for this classifier behavior execution to the given class. // If the given class is a behavior, set the execution to be the object of the object activation of the classifier behavior execution. // Otherwise the class must be an active class, so get an execution object for the classifier behavior for the class. // Set the input parameters for the execution to the given values. // Then start the active behavior of this ClassifierBehaviorExecution object, which will execute the execution object on a separate thread of control. // Debug.println("[execute] Executing behavior for " + classifier.name + "..."); this.classifier = classifier; Object_ object = this.objectActivation.object; if (classifier instanceof Behavior) { this.execution = (Execution)object; } else { this.execution = object.locus.factory.createExecution(classifier.classifierBehavior, object); } if (inputs != null) { for (int i = 0; i < inputs.size(); i++) { ParameterValue input = inputs.getValue(i); this.execution.setParameterValue(input); } } _startObjectBehavior(); Java // Terminate the associated execution. // If the execution is not itself the object of the object activation, then destroy it. //Debug.println("[terminate] Terminating behavior for " + classifier.name + "..."); this.execution.terminate(); if (this.execution != this.objectActivation.object) { this.execution.destroy(); } import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.*; Java // Return the single type of this signal instance. ClassifierList types = new ClassifierList(); types.addValue(this.type); return types; Java // Create a new signal instance with no type or feature values. return new SignalInstance(); Java // Create a new signal instance with the same type and feature values as this signal instance. SignalInstance newValue = (SignalInstance)(super.copy()); newValue.type = this.type; return newValue; An object activation handles the active behavior of an active object. import java.util.Iterator; import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Syntax.CommonBehaviors.Communications.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.Loci.LociL1.*; The executing classifier behaviors for this object activation. The set of event accepters waiting for signals to be received by the object of this object activation. The pool of signals sent to the object of this object activation, pending dispatching as events. (All the data values in the pool must be signal instances -- that is, they must have a single type that is a signal.) The object whose active behavior is being handled by this active object. Java // Stop this object activation by terminating all classifier behavior executions. ClassifierBehaviorExecutionList classifierBehaviorExecutions = this.classifierBehaviorExecutions; for (int i = 0; i < classifierBehaviorExecutions.size(); i++) { ClassifierBehaviorExecution classifierBehaviorExecution = classifierBehaviorExecutions.getValue(i); classifierBehaviorExecution.terminate(); } Java // Register the given event accepter to wait for a dispatched signal event. Debug.println("[register] object = " + this.object); Debug.println("[register] accepter = " + accepter); this.waitingEventAccepters.addValue(accepter); Java // Remove the given event accepter for the list of waiting event accepters. Debug.println("[unregister] object = " + this.object); Debug.println("[unregister] accepter = " + accepter); boolean notFound = true; int i = 1; while (notFound & i <= this.waitingEventAccepters.size()) { if (this.waitingEventAccepters.getValue(i-1) == accepter) { this.waitingEventAccepters.remove(i-1); notFound = false; } i = i + 1; } Java // Get the next signal instance out of the event pool. // If there is one or more waiting event accepters with triggers that match the signal instance, then dispatch it to exactly one of those waiting accepters. if (this.eventPool.size() > 0) { SignalInstance signalInstance = this.getNextEvent(); Debug.println("[dispatchNextEvent] signalInstance = " + signalInstance); intList matchingEventAccepterIndexes = new intList(); EventAccepterList waitingEventAccepters = this.waitingEventAccepters; for (int i = 0; i < waitingEventAccepters.size(); i++) { EventAccepter eventAccepter = waitingEventAccepters.getValue(i); if (eventAccepter.match(signalInstance)) { matchingEventAccepterIndexes.addValue(i); } } if (matchingEventAccepterIndexes.size() > 0) { // *** Choose one matching event accepter non-deterministically. *** int j = ((ChoiceStrategy)this.object.locus.factory.getStrategy("choice")).choose(matchingEventAccepterIndexes.size()); EventAccepter selectedEventAccepter = this.waitingEventAccepters.getValue(matchingEventAccepterIndexes.getValue(j-1)); this.waitingEventAccepters.removeValue(j-1); selectedEventAccepter.accept(signalInstance); } } Java // Get the next event from the event pool, using a get next event strategy. return ((GetNextEventStrategy)this.object.locus.factory.getStrategy("getNextEvent")).getNextEvent(this); Java // Add the given signal instance to the event pool and signal that a new signal instance has arrived. this.eventPool.addValue((SignalInstance)(signalInstance.copy())); _send(new ArrivalSignal()); Java // Start the event dispatch loop for this object activation (if it has not already been started). // If a classifier is given that is a type of the object of this object activation and there is not already a classifier behavior execution for it, // then create a classifier behavior execution for it. // Otherwise, create a classifier behavior execution for each of the types of the object of this object activation which has a classifier behavior or which is a behavior itself // and for which there is not currently a classifier behavior execution. // Start EventDispatchLoop _startObjectBehavior(); if (classifier == null) { Debug.println("[startBehavior] Starting behavior for all classifiers..."); // *** Start all classifier behaviors concurrently. *** Class_List types = this.object.types; for (Iterator i = types.iterator(); i.hasNext();) { Class_ type = (Class_)i.next(); if (type instanceof Behavior | type.classifierBehavior != null) { this.startBehavior(type, new ParameterValueList()); } } } else { Debug.println("[startBehavior] Starting behavior for " + classifier.name + "..."); boolean notYetStarted = true; int i = 1; while (notYetStarted & i <= this.classifierBehaviorExecutions.size()) { notYetStarted = (this.classifierBehaviorExecutions.getValue(i-1).classifier != classifier); i = i + 1; } if (notYetStarted) { ClassifierBehaviorExecution newExecution = new ClassifierBehaviorExecution(); newExecution.objectActivation = this; this.classifierBehaviorExecutions.addValue(newExecution); newExecution.execute(classifier, inputs); } } A get next event strategy is a semantic strategy that determines the order in which signal instances are retrieved from the event pool of an object activation. Java // Get next event strategies are always named "getNextEvent". return "getNextEvent"; Get the next event from the event pool of the given object activation. The event is removed from the pool. A FIFO get next event strategy gets events in first-in first-out order. Java // Get the first event from the given event pool. The event is removed from the pool. SignalInstance signalInstance = objectActivation.eventPool.getValue(0); objectActivation.eventPool.removeValue(0); return signalInstance; A choice strategy is used to represent the behavior of making an arbitrary non-deterministic choice. A valid execution may use ANY choice strategy for choosing one element from a given set. Java // The name of a choice strategy is always "choice". return "choice"; Choose an integer from 1 to the given size. [The size must be greater than 0.] An execution factory is used to create objects that represent the execution of a behavior, the evaluation of a value specification or the activation of an activity node. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; The locus at which this factory resides. The set of opaque behavior executions to be used to execute the primitive behaviors known to the factory. The set of primitive types that have corresponding literal value specifications. Must include Integer, Boolean, String and UnlimitedNatural. The set of semantic strategies currently registered with this execution factory. Java // Create an execution object for a given behavior. // The execution will take place at the locus of the factory in the given context. // If the context is empty, the execution is assumed to provide its own context. Execution execution; if (behavior instanceof OpaqueBehavior) { execution = this.instantiateOpaqueBehaviorExecution((OpaqueBehavior)behavior); } else { execution = (Execution)this.instantiateVisitor(behavior); execution.types.addValue(behavior); execution.createFeatureValues(); } this.locus.add(execution); if (context == null) { execution.context = execution; } else { execution.context = context; } return execution; Java // Create an evaluation object for a given value specification. // The evaluation will take place at the locus of the factory. Evaluation evaluation = (Evaluation)this.instantiateVisitor(specification); evaluation.specification = specification; evaluation.locus = this.locus; return evaluation; Java // Return a copy of the prototype for the primitive behavior execution of the given opaque behavior. OpaqueBehaviorExecution execution = null; int i = 1; while (execution == null & i <= this.primitiveBehaviorPrototypes.size()) { // Debug.println("[instantiateOpaqueExecution] Checking " + this.primitiveBehaviorPrototypes.getValue(i).objectId() + "..."); OpaqueBehaviorExecution prototype = this.primitiveBehaviorPrototypes.getValue(i-1); if (prototype.getBehavior() == behavior) { execution = (OpaqueBehaviorExecution)(prototype.copy()); } i = i + 1; } if (execution == null) { Debug.println("[instantiateOpaqueExecution] No prototype execution found for " + behavior.name + "."); } return execution; Java // Add an opaque behavior execution to use as a prototype for instantiating the corresponding primitive opaque behavior. // Precondition: No primitive behavior prototype for the type of the given execution should already exist. this.primitiveBehaviorPrototypes.addValue(execution); Java // Add the given primitive type as a built-in type. // Precondition: No built-in type with the same name should already exist. this.builtInTypes.addValue(type); Java // Return the built-in type with the given name. PrimitiveType type = null; int i = 1; while (type == null & i <= this.builtInTypes.size()) { PrimitiveType primitiveType = this.builtInTypes.getValue(i-1); if (primitiveType.name.equals(name)) { type = primitiveType; } i = i + 1; } return type; Java // Set the strategy for a semantic variation point. Any existing strategy for the same SVP is replaced. int i = this.getStrategyIndex(strategy.getName()); if (i <= this.strategies.size()) { this.strategies.removeValue(i-1); } this.strategies.addValue(strategy); Java // Get the strategy with the given name. int i = this.getStrategyIndex(name); SemanticStrategy strategy = null; if (i <= this.strategies.size()) { strategy = this.strategies.getValue(i-1); } return strategy; Java // Get the index of the strategy with the given name. // If there is no such strategy, return the size of the strategies list. SemanticStrategyList strategies = this.strategies; int i = 1; boolean unmatched = true; while (unmatched & (i <= strategies.size())) { if (strategies.getValue(i-1).getName().equals(name)) { unmatched = false; } else { i = i + 1; } } return i; Instantiate a visitor object for the given element. An executor is used to execute behaviors and evaluation value specifications. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; The locus at which this executor resides. Java // Execute the given behavior with the given input values in the given context, producing the given output values. // There must be one input parameter value for each input (in or in-out) parameter of the behavior. // The returned values include one parameter value for each output (in-out, out or return) parameter of the behavior. // The execution instance is destroyed at completion. Execution execution = this.locus.factory.createExecution(behavior, context); for (int i = 0; i < inputs.size(); i++) { execution.setParameterValue(inputs.getValue(i)); } execution.execute(); ParameterValueList outputValues = execution.getOutputParameterValues(); execution.destroy(); return outputValues; Java // Evaluate the given value specification, returning the specified value. // Debug.println("[evaluate] Start..."); return this.locus.factory.createEvaluation(specification).evaluate(); Java // Instantiate the given class and start any behavior of the resulting object. // (The behavior of an object includes any classifier behaviors for an active object or the class of the object itself, if that is a behavior.) Debug.println("[start] Starting " + type.name + "..."); Object_ object = this.locus.instantiate(type); Debug.println("[start] Object = " + object); object.startBehavior(type, inputs); Reference reference = new Reference(); reference.referent = object; return reference; Java // Always choose one. return 1; A locus is a place at which extensional values (objects or links) can exist. The extent of a class or association is the set of objects or links of that type that exist at a certain locus. A locus also has an executor and a factory associated with it, used to execute behaviors as a result of requests dispatched to objects at the locus. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Syntax.CommonBehaviors.BasicBehaviors.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; import fUML.Semantics.CommonBehaviors.BasicBehaviors.*; The executor to be used at this locus. The factory to be used at this locus. Java // Set the executor for this locus. this.executor = executor; this.executor.locus = this; Java // Set the factory for this locus. this.factory = factory; this.factory.locus = this; Java // Return the set of extensional values at this locus which have the given classifier as a type. ExtensionalValueList extent = new ExtensionalValueList(); ExtensionalValueList extensionalValues = this.extensionalValues; for (int i = 0; i < extensionalValues.size(); i++) { ExtensionalValue value = extensionalValues.getValue(i); ClassifierList types = value.getTypes(); boolean conforms = false; int j = 1; while (!conforms & j <= types.size()) { conforms = this.conforms(types.getValue(j-1), classifier); j = j + 1; } if (conforms) { extent.addValue(value); } } return extent; Java // Add the given extensional value to this locus value.locus = this; this.extensionalValues.addValue(value); Java // Remove the given extensional value from this locus. value.locus = null; boolean notFound = true; int i = 1; while (notFound & i <= this.extensionalValues.size()) { if (this.extensionalValues.getValue(i-1) == value) { this.extensionalValues.remove(i-1); notFound = false; } i = i + 1; } Java // Instantiate the given class at this locus. Object_ object = null; if (type instanceof Behavior) { object = this.factory.createExecution((Behavior)type, null); } else { object = new Object_(); object.types.addValue(type); object.createFeatureValues(); this.add(object); } return object; Java // Test if a type conforms to a given classifier, that is, the type is equal to or a descendant of the classifier. boolean doesConform = false; if (type == classifier) { doesConform = true; } else { int i = 1; while (!doesConform & i <= type.general.size()) { doesConform = this.conforms(type.general.getValue(i-1), classifier); i = i + 1; } } return doesConform; The common base class for semantic strategy classes. A semantic strategy class specifies the behavior to be used at a specific semantic variatio point. Return the name of this strategy, as defined for the semantic variation point to which the strategy applies. The common base class for semantic visitor classes. Java Debug.println("[_endIsolation] End isolation."); Java Debug.println("[_beginIsolation] Begin isolation."); An execution factory is used to create objects that represent the execution of a behavior, the evaluation of a value specification or the activation of an activity node. This class only handles elements available at Conformance Level 1. import fUML.Syntax.*; import fUML.Syntax.Classes.Kernel.*; import fUML.Semantics.*; import fUML.Semantics.Classes.Kernel.*; Java // Instantiate a visitor object for the given element (at Conformance Level 1) SemanticVisitor visitor = null; if (element instanceof LiteralBoolean) { visitor = new LiteralBooleanEvaluation(); } else if (element instanceof fUML.Syntax.Classes.Kernel.LiteralString) { visitor = new LiteralStringEvaluation(); } else if (element instanceof fUML.Syntax.Classes.Kernel.LiteralNull) { visitor = new LiteralNullEvaluation(); } else if (element instanceof fUML.Syntax.Classes.Kernel.InstanceValue) { visitor = new InstanceValueEvaluation(); } else if (element instanceof fUML.Syntax.Classes.Kernel.LiteralUnlimitedNatural) { visitor = new LiteralUnlimitedNaturalEvaluation(); } else if (element instanceof fUML.Syntax.Classes.Kernel.LiteralInteger) { visitor = new LiteralIntegerEvaluation(); } else if (element instanceof LiteralReal) { visitor = new LiteralRealEvaluation(); } return visitor; An execution factory is used to create objects that represent the execution of a behavior, the evaluation of a value specification or the activation of an activity node. This class only handles elements available at Conformance Level 2. import fUML.Syntax.*; import fUML.Syntax.Activities.IntermediateActivities.*; import fUML.Syntax.Actions.BasicActions.*; import fUML.Syntax.Actions.IntermediateActions.*; import fUML.Semantics.*; import fUML.Semantics.Activities.IntermediateActivities.*; import fUML.Semantics.Actions.BasicActions.*; import fUML.Semantics.Actions.IntermediateActions.*; import fUML.Semantics.Loci.LociL1.*; Java // Instantiate a visitor object for the given element (at Conformance Level 2) SemanticVisitor visitor = null; if (element instanceof Activity) { visitor = new ActivityExecution(); } else if (element instanceof ActivityParameterNode) { visitor = new ActivityParameterNodeActivation(); } else if (element instanceof InitialNode) { visitor = new InitialNodeActivation(); } else if (element instanceof ActivityFinalNode) { visitor = new ActivityFinalNodeActivation(); } else if (element instanceof FlowFinalNode) { visitor = new FlowFinalNodeActivation(); } else if (element instanceof JoinNode) { visitor = new JoinNodeActivation(); } else if (element instanceof MergeNode) { visitor = new MergeNodeActivation(); } else if (element instanceof ForkNode) { visitor = new ForkNodeActivation(); } else if (element instanceof DecisionNode) { visitor = new DecisionNodeActivation(); } else if (element instanceof InputPin) { visitor = new InputPinActivation(); } else if (element instanceof OutputPin) { visitor = new OutputPinActivation(); } else if (element instanceof CallBehaviorAction) { visitor = new CallBehaviorActionActivation(); } else if (element instanceof CallOperationAction) { visitor = new CallOperationActionActivation(); } else if (element instanceof SendSignalAction) { visitor = new SendSignalActionActivation(); } else if (element instanceof ReadSelfAction) { visitor = new ReadSelfActionActivation(); } else if (element instanceof TestIdentityAction) { visitor = new TestIdentityActionActivation(); } else if (element instanceof ValueSpecificationAction) { visitor = new ValueSpecificationActionActivation(); } else if (element instanceof CreateObjectAction) { visitor = new CreateObjectActionActivation(); } else if (element instanceof DestroyObjectAction) { visitor = new DestroyObjectActionActivation(); } else if (element instanceof ReadStructuralFeatureAction) { visitor = new ReadStructuralFeatureActionActivation(); } else if (element instanceof ClearStructuralFeatureAction) { visitor = new ClearStructuralFeatureActionActivation(); } else if (element instanceof AddStructuralFeatureValueAction) { visitor = new AddStructuralFeatureValueActionActivation(); } else if (element instanceof RemoveStructuralFeatureValueAction) { visitor = new RemoveStructuralFeatureValueActionActivation(); } else if (element instanceof ReadLinkAction) { visitor = new ReadLinkActionActivation(); } else if (element instanceof ClearAssociationAction) { visitor = new ClearAssociationActionActivation(); } else if (element instanceof CreateLinkAction) { visitor = new CreateLinkActionActivation(); } else if (element instanceof DestroyLinkAction) { visitor = new DestroyLinkActionActivation(); } else { visitor = super.instantiateVisitor(element); } return visitor; An execution factory is used to create objects that represent the execution of a behavior, the evaluation of a value specification or the activation of an activity node. This class only handles elements available at Conformance Level 3. import fUML.Syntax.*; import fUML.Syntax.Activities.CompleteStructuredActivities.*; import fUML.Syntax.Activities.ExtraStructuredActivities.*; import fUML.Syntax.Actions.CompleteActions.*; import fUML.Semantics.*; import fUML.Semantics.Activities.CompleteStructuredActivities.*; import fUML.Semantics.Activities.ExtraStructuredActivities.*; import fUML.Semantics.Actions.CompleteActions.*; import fUML.Semantics.Loci.LociL1.*; import fUML.Semantics.Loci.LociL2.*; Java // Instantiate a visitor object for the given element (at Conformance Level 3) SemanticVisitor visitor = null; if (element instanceof ConditionalNode) { visitor = new ConditionalNodeActivation(); } else if (element instanceof LoopNode) { visitor = new LoopNodeActivation(); } else if (element instanceof ExpansionRegion) { visitor = new ExpansionRegionActivation(); } // Note: Since ConditionalNode, LoopNode and ExpansionRegion are subclasses of // StructuredActivityNode, element must be tested against the three subclasses before // the superclass else if (element instanceof StructuredActivityNode) { visitor = new StructuredActivityNodeActivation(); } else if (element instanceof ExpansionNode) { visitor = new ExpansionNodeActivation(); } else if (element instanceof ReadExtentAction) { visitor = new ReadExtentActionActivation(); } else if (element instanceof ReadIsClassifiedObjectAction) { visitor = new ReadIsClassifiedObjectActionActivation(); } else if (element instanceof ReclassifyObjectAction) { visitor = new ReclassifyObjectActionActivation(); } else if (element instanceof StartObjectBehaviorAction) { visitor = new StartObjectBehaviorActionActivation(); } else if (element instanceof StartClassifierBehaviorAction) { visitor = new StartClassifierBehaviorActionActivation(); } else if (element instanceof AcceptEventAction) { visitor = new AcceptEventActionActivation(); } else if (element instanceof ReduceAction) { visitor = new ReduceActionActivation(); } else { visitor = super.instantiateVisitor(element); } return visitor; METAMODEL MARTE4fUML New properties for Locus Package: Semantics::Equation Used to indicate absence of value in an action Accept An instance of the Signal called AbsentSignal Manually embedded